From b8aa35ab98da2f9e869d7606b4e6f9f2f4e361fb Mon Sep 17 00:00:00 2001 From: 0x78f1935 Date: Tue, 22 Apr 2025 00:29:44 +0200 Subject: [PATCH 01/18] ADD: Docker build which allows us to run server containerized --- .docker/services/turnstile/solver.Dockerfile | 21 ++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 .docker/services/turnstile/solver.Dockerfile diff --git a/.docker/services/turnstile/solver.Dockerfile b/.docker/services/turnstile/solver.Dockerfile new file mode 100644 index 0000000..7896f1c --- /dev/null +++ b/.docker/services/turnstile/solver.Dockerfile @@ -0,0 +1,21 @@ +FROM python:3.13.3 + +# Prevent interactive prompts during package installs +ENV DEBIAN_FRONTEND=noninteractive + +# Install requirements +RUN pip install playwright && \ + playwright install chromium --with-deps + +WORKDIR /workspaceFolder +COPY . . +RUN pip install -r requirements.txt +RUN pip install . + +WORKDIR /workspaceFolder/src/turnstile_solver +RUN echo '#!/bin/bash\n\ + python main.py --headless\n\ + exec "$@"' > /workspaceFolder/entrypoint.sh + +RUN chmod +x /workspaceFolder/entrypoint.sh +ENTRYPOINT [ "/workspaceFolder/entrypoint.sh" ] \ No newline at end of file From f42bc02e388fd3f293f7fad23aef2179388af389 Mon Sep 17 00:00:00 2001 From: 0x78f1935 Date: Tue, 22 Apr 2025 00:30:12 +0200 Subject: [PATCH 02/18] ADD: Docker compose file which is able to spin up the dockerfile --- docker-compose.yaml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 docker-compose.yaml diff --git a/docker-compose.yaml b/docker-compose.yaml new file mode 100644 index 0000000..6b7e52c --- /dev/null +++ b/docker-compose.yaml @@ -0,0 +1,17 @@ +services: + solver: + container_name: solver + hostname: solver + build: + context: . + dockerfile: ./.docker/services/turnstile/solver.Dockerfile + restart: always + ports: + - 8088:8088 + networks: + - solver + +networks: + solver: + name: solver + driver: bridge From 5f80c37a87e79bcda25a9f2dc6f55ac391dda4ee Mon Sep 17 00:00:00 2001 From: 0x78f1935 Date: Tue, 22 Apr 2025 00:31:03 +0200 Subject: [PATCH 03/18] CHANGE: Absolute imports to relative imports --- src/turnstile_solver/main.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/turnstile_solver/main.py b/src/turnstile_solver/main.py index 9f4cd82..01dbe65 100644 --- a/src/turnstile_solver/main.py +++ b/src/turnstile_solver/main.py @@ -18,15 +18,15 @@ from rich.text import Text from multiprocessing import Process -from . import constants as c -from .proxy import Proxy -from .proxy_provider import ProxyProvider -from .custom_rich_help_formatter import CustomRichHelpFormatter -from .solver_console import SolverConsole -from .solver_console_highlighter import SolverConsoleHighlighter -from .solver import TurnstileSolver -from .utils import init_logger, simulate_intensive_task, get_file_handler, load_proxy_param -from .turnstile_solver_server import TurnstileSolverServer +from turnstile_solver import constants as c +from turnstile_solver.proxy import Proxy +from turnstile_solver.proxy_provider import ProxyProvider +from turnstile_solver.custom_rich_help_formatter import CustomRichHelpFormatter +from turnstile_solver.solver_console import SolverConsole +from turnstile_solver.solver_console_highlighter import SolverConsoleHighlighter +from turnstile_solver.solver import TurnstileSolver +from turnstile_solver.utils import init_logger, simulate_intensive_task, get_file_handler, load_proxy_param +from turnstile_solver.turnstile_solver_server import TurnstileSolverServer _console = SolverConsole() From b7310ba4984bbdadb9007c325402938fbde4c0da Mon Sep 17 00:00:00 2001 From: 0x78f1935 Date: Tue, 22 Apr 2025 00:31:29 +0200 Subject: [PATCH 04/18] CHANGE: Hide the fact we run an automated browser --- src/turnstile_solver/solver.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/turnstile_solver/solver.py b/src/turnstile_solver/solver.py index f72d6b8..c5fb597 100644 --- a/src/turnstile_solver/solver.py +++ b/src/turnstile_solver/solver.py @@ -296,9 +296,15 @@ async def get_browser(self, browser: Browser | None = await playwright.chromium.launch( executable_path=self.browser_executable_path, # channel=channel, - args=self.browser_args, headless=self.headless, proxy=proxy.dict() if proxy else None, + args=[ + "--no-sandbox", + "--disable-dev-shm-usage", + "--disable-setuid-sandbox", + "--disable-software-rasterizer", + *self.browser_args, + ] ) return browser, playwright From ae9ad690ec867b0fa66c63be7f6bd4b0d89162e6 Mon Sep 17 00:00:00 2001 From: 0x78f1935 Date: Tue, 22 Apr 2025 00:50:37 +0200 Subject: [PATCH 05/18] ADD: Image name --- docker-compose.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/docker-compose.yaml b/docker-compose.yaml index 6b7e52c..b29d639 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -1,6 +1,7 @@ services: solver: container_name: solver + image: turnstile_solver hostname: solver build: context: . From c7d279b05c5cf905c4cf62cb4bcd30bc69f78c48 Mon Sep 17 00:00:00 2001 From: 0x78f1935 Date: Tue, 22 Apr 2025 15:45:05 +0200 Subject: [PATCH 06/18] FIX: Hardcoded browser arguments --- .docker/services/turnstile/solver.Dockerfile | 4 ++-- src/turnstile_solver/solver.py | 8 +------- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/.docker/services/turnstile/solver.Dockerfile b/.docker/services/turnstile/solver.Dockerfile index 7896f1c..b51d036 100644 --- a/.docker/services/turnstile/solver.Dockerfile +++ b/.docker/services/turnstile/solver.Dockerfile @@ -14,8 +14,8 @@ RUN pip install . WORKDIR /workspaceFolder/src/turnstile_solver RUN echo '#!/bin/bash\n\ - python main.py --headless\n\ + python main.py --headless --browser-args "--no-sandbox --disable-dev-shm-usage --disable-setuid-sandbox --disable-software-rasterizer"\n\ exec "$@"' > /workspaceFolder/entrypoint.sh RUN chmod +x /workspaceFolder/entrypoint.sh -ENTRYPOINT [ "/workspaceFolder/entrypoint.sh" ] \ No newline at end of file +ENTRYPOINT [ "/workspaceFolder/entrypoint.sh" ] diff --git a/src/turnstile_solver/solver.py b/src/turnstile_solver/solver.py index c5fb597..f72d6b8 100644 --- a/src/turnstile_solver/solver.py +++ b/src/turnstile_solver/solver.py @@ -296,15 +296,9 @@ async def get_browser(self, browser: Browser | None = await playwright.chromium.launch( executable_path=self.browser_executable_path, # channel=channel, + args=self.browser_args, headless=self.headless, proxy=proxy.dict() if proxy else None, - args=[ - "--no-sandbox", - "--disable-dev-shm-usage", - "--disable-setuid-sandbox", - "--disable-software-rasterizer", - *self.browser_args, - ] ) return browser, playwright From 5f2aa23ba3c2e501ca8a3a31d2d58c0eac15e62e Mon Sep 17 00:00:00 2001 From: 0x78f1935 Date: Tue, 22 Apr 2025 15:47:28 +0200 Subject: [PATCH 07/18] CHANGE: Convert all relative imports to absolute imports --- src/turnstile_solver/__init__.py | 8 ++++---- src/turnstile_solver/__main__.py | 2 +- src/turnstile_solver/browser_context_pool.py | 10 +++++----- src/turnstile_solver/page_pool.py | 2 +- src/turnstile_solver/proxy_provider.py | 2 +- src/turnstile_solver/solver.py | 12 ++++++------ src/turnstile_solver/solver_console.py | 4 ++-- src/turnstile_solver/turnstile_result.py | 4 ++-- src/turnstile_solver/turnstile_solver_server.py | 12 ++++++------ src/turnstile_solver/utils.py | 2 +- 10 files changed, 29 insertions(+), 29 deletions(-) diff --git a/src/turnstile_solver/__init__.py b/src/turnstile_solver/__init__.py index 23bb1e5..4b9346c 100644 --- a/src/turnstile_solver/__init__.py +++ b/src/turnstile_solver/__init__.py @@ -1,4 +1,4 @@ -from .solver import TurnstileSolver -from .turnstile_solver_server import TurnstileSolverServer -from .constants import HOST, PORT -from .main import main, run_server, main_cli +from turnstile_solver.solver import TurnstileSolver +from turnstile_solver.turnstile_solver_server import TurnstileSolverServer +from turnstile_solver.constants import HOST, PORT +from turnstile_solver.main import main, run_server, main_cli diff --git a/src/turnstile_solver/__main__.py b/src/turnstile_solver/__main__.py index 79ae050..76a8b7f 100644 --- a/src/turnstile_solver/__main__.py +++ b/src/turnstile_solver/__main__.py @@ -1,6 +1,6 @@ import asyncio -from .main import main +from turnstile_solver.main import main if __name__ == '__main__': asyncio.run(main()) diff --git a/src/turnstile_solver/browser_context_pool.py b/src/turnstile_solver/browser_context_pool.py index abeb649..d774fc4 100644 --- a/src/turnstile_solver/browser_context_pool.py +++ b/src/turnstile_solver/browser_context_pool.py @@ -4,13 +4,13 @@ from patchright.async_api import Browser -from .constants import MAX_PAGES_PER_CONTEXT, MAX_CONTEXTS -from .page_pool import PagePool -from .pool import Pool -from .proxy_provider import ProxyProvider +from turnstile_solver.constants import MAX_PAGES_PER_CONTEXT, MAX_CONTEXTS +from turnstile_solver.page_pool import PagePool +from turnstile_solver.pool import Pool +from turnstile_solver.proxy_provider import ProxyProvider if TYPE_CHECKING: - from .solver import TurnstileSolver + from turnstile_solver.solver import TurnstileSolver logger = logging.getLogger(__name__) diff --git a/src/turnstile_solver/page_pool.py b/src/turnstile_solver/page_pool.py index 9b53ca1..997997a 100644 --- a/src/turnstile_solver/page_pool.py +++ b/src/turnstile_solver/page_pool.py @@ -3,7 +3,7 @@ from patchright.async_api import BrowserContext, Page, Route from turnstile_solver.pool import Pool -from .constants import MAX_PAGES_PER_CONTEXT +from turnstile_solver.constants import MAX_PAGES_PER_CONTEXT logger = logging.getLogger(__name__) diff --git a/src/turnstile_solver/proxy_provider.py b/src/turnstile_solver/proxy_provider.py index 69f9c9e..b31c5e0 100644 --- a/src/turnstile_solver/proxy_provider.py +++ b/src/turnstile_solver/proxy_provider.py @@ -1,7 +1,7 @@ import logging from pathlib import Path -from .proxy import Proxy +from turnstile_solver.proxy import Proxy logger = logging.getLogger(__name__) diff --git a/src/turnstile_solver/solver.py b/src/turnstile_solver/solver.py index f72d6b8..e3bf23d 100644 --- a/src/turnstile_solver/solver.py +++ b/src/turnstile_solver/solver.py @@ -5,12 +5,12 @@ from typing import Callable, Awaitable from patchright.async_api import async_playwright, Page, BrowserContext, Browser, Playwright -from . import constants as c -from .enums import CaptchaApiMessageEvent -from .proxy import Proxy -from .solver_console import SolverConsole -from .turnstile_result import TurnstileResult -from .turnstile_solver_server import TurnstileSolverServer, CAPTCHA_EVENT_CALLBACK_ENDPOINT +from turnstile_solver import constants as c +from turnstile_solver.enums import CaptchaApiMessageEvent +from turnstile_solver.proxy import Proxy +from turnstile_solver.solver_console import SolverConsole +from turnstile_solver.turnstile_result import TurnstileResult +from turnstile_solver.turnstile_solver_server import TurnstileSolverServer, CAPTCHA_EVENT_CALLBACK_ENDPOINT logger = logging.getLogger(__name__) diff --git a/src/turnstile_solver/solver_console.py b/src/turnstile_solver/solver_console.py index a1766c4..251670a 100644 --- a/src/turnstile_solver/solver_console.py +++ b/src/turnstile_solver/solver_console.py @@ -1,8 +1,8 @@ from rich.console import Console from rich.theme import Theme -from .constants import CONSOLE_THEME_STYLES -from .solver_console_highlighter import SolverConsoleHighlighter +from turnstile_solver.constants import CONSOLE_THEME_STYLES +from turnstile_solver.solver_console_highlighter import SolverConsoleHighlighter MAX_CONSOLE_WIDTH = 200 diff --git a/src/turnstile_solver/turnstile_result.py b/src/turnstile_solver/turnstile_result.py index c8c947d..2c60c82 100644 --- a/src/turnstile_solver/turnstile_result.py +++ b/src/turnstile_solver/turnstile_result.py @@ -7,8 +7,8 @@ from patchright.async_api import BrowserContext, Page -from .enums import CaptchaApiMessageEvent -from .utils import password +from turnstile_solver.enums import CaptchaApiMessageEvent +from turnstile_solver.utils import password logger = logging.getLogger(__name__) diff --git a/src/turnstile_solver/turnstile_solver_server.py b/src/turnstile_solver/turnstile_solver_server.py index f85c792..f1ddcc6 100644 --- a/src/turnstile_solver/turnstile_solver_server.py +++ b/src/turnstile_solver/turnstile_solver_server.py @@ -10,12 +10,12 @@ from quart import Quart, Response, request -from .enums import CaptchaApiMessageEvent -from .constants import PORT, HOST, CAPTCHA_EVENT_CALLBACK_ENDPOINT, MAX_CONTEXTS, MAX_PAGES_PER_CONTEXT -from .proxy_provider import ProxyProvider -from .solver_console import SolverConsole -from .constants import SECRET -from .browser_context_pool import BrowserContextPool +from turnstile_solver.enums import CaptchaApiMessageEvent +from turnstile_solver.constants import PORT, HOST, CAPTCHA_EVENT_CALLBACK_ENDPOINT, MAX_CONTEXTS, MAX_PAGES_PER_CONTEXT +from turnstile_solver.proxy_provider import ProxyProvider +from turnstile_solver.solver_console import SolverConsole +from turnstile_solver.constants import SECRET +from turnstile_solver.browser_context_pool import BrowserContextPool if TYPE_CHECKING: from .solver import TurnstileSolver diff --git a/src/turnstile_solver/utils.py b/src/turnstile_solver/utils.py index 23227e4..ee9c8a1 100644 --- a/src/turnstile_solver/utils.py +++ b/src/turnstile_solver/utils.py @@ -6,7 +6,7 @@ from faker import Faker from rich.logging import RichHandler -from .solver_console import SolverConsole +from turnstile_solver.solver_console import SolverConsole _faker = Faker(locale='en_US') From 44f961e692e67b2423a52d07cd8cabac21e98fd0 Mon Sep 17 00:00:00 2001 From: 0x78f1935 Date: Tue, 22 Apr 2025 15:50:41 +0200 Subject: [PATCH 08/18] ADD: VSC Dev environment --- .vscode/launch.json | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 .vscode/launch.json diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..856f7d2 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,25 @@ +{ + "configurations": [ + { + "name": "Turnstile: Headless", + "type": "debugpy", + "request": "launch", + "module": "turnstile_solver", + "args": [ + "--headless", + "--port", + "8088" + ] + }, + { + "name": "Turnstile: None-Headless", + "type": "debugpy", + "request": "launch", + "module": "turnstile_solver", + "args": [ + "--port", + "8088" + ] + } + ] +} \ No newline at end of file From 194dc9369c6c0df01296fd346eda3f88b3ac76fa Mon Sep 17 00:00:00 2001 From: 0x78f1935 Date: Tue, 22 Apr 2025 15:51:14 +0200 Subject: [PATCH 09/18] ADD: Modeline --- src/turnstile_solver/__init__.py | 1 + src/turnstile_solver/__main__.py | 1 + src/turnstile_solver/browser_context_pool.py | 1 + src/turnstile_solver/constants.py | 1 + src/turnstile_solver/custom_rich_help_formatter.py | 1 + src/turnstile_solver/enums.py | 1 + src/turnstile_solver/main.py | 1 + src/turnstile_solver/page_pool.py | 1 + src/turnstile_solver/pool.py | 1 + src/turnstile_solver/proxy.py | 1 + src/turnstile_solver/proxy_provider.py | 1 + src/turnstile_solver/solver.py | 1 + src/turnstile_solver/solver_console.py | 1 + src/turnstile_solver/solver_console_highlighter.py | 1 + src/turnstile_solver/turnstile_result.py | 1 + src/turnstile_solver/turnstile_site.py | 2 +- src/turnstile_solver/turnstile_solver_server.py | 1 + src/turnstile_solver/utils.py | 1 + tests/conftest.py | 1 + tests/proxy_provider.py | 1 + tests/test_solver.py | 1 + 21 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/turnstile_solver/__init__.py b/src/turnstile_solver/__init__.py index 4b9346c..555ffb2 100644 --- a/src/turnstile_solver/__init__.py +++ b/src/turnstile_solver/__init__.py @@ -1,3 +1,4 @@ +# -*- mode: python ; coding: utf-8 -*- from turnstile_solver.solver import TurnstileSolver from turnstile_solver.turnstile_solver_server import TurnstileSolverServer from turnstile_solver.constants import HOST, PORT diff --git a/src/turnstile_solver/__main__.py b/src/turnstile_solver/__main__.py index 76a8b7f..296e4c2 100644 --- a/src/turnstile_solver/__main__.py +++ b/src/turnstile_solver/__main__.py @@ -1,3 +1,4 @@ +# -*- mode: python ; coding: utf-8 -*- import asyncio from turnstile_solver.main import main diff --git a/src/turnstile_solver/browser_context_pool.py b/src/turnstile_solver/browser_context_pool.py index d774fc4..6a52637 100644 --- a/src/turnstile_solver/browser_context_pool.py +++ b/src/turnstile_solver/browser_context_pool.py @@ -1,3 +1,4 @@ +# -*- mode: python ; coding: utf-8 -*- import asyncio import logging from typing import TYPE_CHECKING diff --git a/src/turnstile_solver/constants.py b/src/turnstile_solver/constants.py index 617a941..ceadbb9 100644 --- a/src/turnstile_solver/constants.py +++ b/src/turnstile_solver/constants.py @@ -1,3 +1,4 @@ +# -*- mode: python ; coding: utf-8 -*- import os from pathlib import Path diff --git a/src/turnstile_solver/custom_rich_help_formatter.py b/src/turnstile_solver/custom_rich_help_formatter.py index 9f9527b..601682d 100644 --- a/src/turnstile_solver/custom_rich_help_formatter.py +++ b/src/turnstile_solver/custom_rich_help_formatter.py @@ -1,3 +1,4 @@ +# -*- mode: python ; coding: utf-8 -*- from rich.console import RenderableType from rich_argparse import RichHelpFormatter diff --git a/src/turnstile_solver/enums.py b/src/turnstile_solver/enums.py index 1cf1186..6799104 100644 --- a/src/turnstile_solver/enums.py +++ b/src/turnstile_solver/enums.py @@ -1,3 +1,4 @@ +# -*- mode: python ; coding: utf-8 -*- from enum import Enum diff --git a/src/turnstile_solver/main.py b/src/turnstile_solver/main.py index 01dbe65..cb4accd 100644 --- a/src/turnstile_solver/main.py +++ b/src/turnstile_solver/main.py @@ -1,3 +1,4 @@ +# -*- mode: python ; coding: utf-8 -*- import asyncio import logging diff --git a/src/turnstile_solver/page_pool.py b/src/turnstile_solver/page_pool.py index 997997a..51cfd52 100644 --- a/src/turnstile_solver/page_pool.py +++ b/src/turnstile_solver/page_pool.py @@ -1,3 +1,4 @@ +# -*- mode: python ; coding: utf-8 -*- import logging from patchright.async_api import BrowserContext, Page, Route diff --git a/src/turnstile_solver/pool.py b/src/turnstile_solver/pool.py index d14ec64..8b997c4 100644 --- a/src/turnstile_solver/pool.py +++ b/src/turnstile_solver/pool.py @@ -1,3 +1,4 @@ +# -*- mode: python ; coding: utf-8 -*- import asyncio import logging from collections import deque diff --git a/src/turnstile_solver/proxy.py b/src/turnstile_solver/proxy.py index 9bf9f22..9e56217 100644 --- a/src/turnstile_solver/proxy.py +++ b/src/turnstile_solver/proxy.py @@ -1,3 +1,4 @@ +# -*- mode: python ; coding: utf-8 -*- import json import logging import re diff --git a/src/turnstile_solver/proxy_provider.py b/src/turnstile_solver/proxy_provider.py index b31c5e0..10f398e 100644 --- a/src/turnstile_solver/proxy_provider.py +++ b/src/turnstile_solver/proxy_provider.py @@ -1,3 +1,4 @@ +# -*- mode: python ; coding: utf-8 -*- import logging from pathlib import Path diff --git a/src/turnstile_solver/solver.py b/src/turnstile_solver/solver.py index e3bf23d..210c737 100644 --- a/src/turnstile_solver/solver.py +++ b/src/turnstile_solver/solver.py @@ -1,3 +1,4 @@ +# -*- mode: python ; coding: utf-8 -*- import datetime import logging import time diff --git a/src/turnstile_solver/solver_console.py b/src/turnstile_solver/solver_console.py index 251670a..d6c6b6a 100644 --- a/src/turnstile_solver/solver_console.py +++ b/src/turnstile_solver/solver_console.py @@ -1,3 +1,4 @@ +# -*- mode: python ; coding: utf-8 -*- from rich.console import Console from rich.theme import Theme diff --git a/src/turnstile_solver/solver_console_highlighter.py b/src/turnstile_solver/solver_console_highlighter.py index 75bd591..3cc2e25 100644 --- a/src/turnstile_solver/solver_console_highlighter.py +++ b/src/turnstile_solver/solver_console_highlighter.py @@ -1,3 +1,4 @@ +# -*- mode: python ; coding: utf-8 -*- from rich.highlighter import ReprHighlighter _ORIGINAL_NUMBER_HIGHLIGHTER = r"(?P(? Date: Tue, 22 Apr 2025 15:56:35 +0200 Subject: [PATCH 10/18] CHANGE: playwright into patchright --- .docker/services/turnstile/solver.Dockerfile | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/.docker/services/turnstile/solver.Dockerfile b/.docker/services/turnstile/solver.Dockerfile index b51d036..0ef55f7 100644 --- a/.docker/services/turnstile/solver.Dockerfile +++ b/.docker/services/turnstile/solver.Dockerfile @@ -4,8 +4,8 @@ FROM python:3.13.3 ENV DEBIAN_FRONTEND=noninteractive # Install requirements -RUN pip install playwright && \ - playwright install chromium --with-deps +RUN pip install patchright && \ + patchright install chromium --with-deps WORKDIR /workspaceFolder COPY . . @@ -14,7 +14,10 @@ RUN pip install . WORKDIR /workspaceFolder/src/turnstile_solver RUN echo '#!/bin/bash\n\ - python main.py --headless --browser-args "--no-sandbox --disable-dev-shm-usage --disable-setuid-sandbox --disable-software-rasterizer"\n\ + python main.py \ + --headless \ + --browser-args "--no-sandbox --disable-dev-shm-usage --disable-setuid-sandbox --disable-software-rasterizer"\ + \n\ exec "$@"' > /workspaceFolder/entrypoint.sh RUN chmod +x /workspaceFolder/entrypoint.sh From b802d879a8b99554607465d0e45a1b666356a22b Mon Sep 17 00:00:00 2001 From: 0x78f1935 Date: Tue, 22 Apr 2025 16:03:31 +0200 Subject: [PATCH 11/18] ADD: Missing flags --- src/turnstile_solver/solver.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/turnstile_solver/solver.py b/src/turnstile_solver/solver.py index 210c737..e29ec73 100644 --- a/src/turnstile_solver/solver.py +++ b/src/turnstile_solver/solver.py @@ -18,11 +18,13 @@ BROWSER_ARGS = { "--disable-blink-features=AutomationControlled", # avoid navigator.webdriver detection "--no-sandbox", + "--disable-setuid-sandbox", "--disable-dev-shm-usage", "--disable-background-networking", "--disable-background-timer-throttling", "--disable-backgrounding-occluded-windows", "--disable-renderer-backgrounding", + "--disable-software-rasterizer", '--disable-application-cache', '--disable-field-trial-config', '--export-tagged-pdf', From acc121065a1e1a065fb4fa2c5ca00457a3d2f07c Mon Sep 17 00:00:00 2001 From: 0x78f1935 Date: Tue, 22 Apr 2025 16:16:47 +0200 Subject: [PATCH 12/18] ADD: Healthcheck and xvfb --- .docker/services/turnstile/solver.Dockerfile | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/.docker/services/turnstile/solver.Dockerfile b/.docker/services/turnstile/solver.Dockerfile index 0ef55f7..953ea22 100644 --- a/.docker/services/turnstile/solver.Dockerfile +++ b/.docker/services/turnstile/solver.Dockerfile @@ -3,6 +3,9 @@ FROM python:3.13.3 # Prevent interactive prompts during package installs ENV DEBIAN_FRONTEND=noninteractive +# Install xvfb +RUN apt-get update && apt-get install -y xvfb x11-apps + # Install requirements RUN pip install patchright && \ patchright install chromium --with-deps @@ -14,11 +17,13 @@ RUN pip install . WORKDIR /workspaceFolder/src/turnstile_solver RUN echo '#!/bin/bash\n\ - python main.py \ - --headless \ - --browser-args "--no-sandbox --disable-dev-shm-usage --disable-setuid-sandbox --disable-software-rasterizer"\ - \n\ - exec "$@"' > /workspaceFolder/entrypoint.sh + xvfb-run --auto-servernum --server-args="-screen 0 1024x720x24" \\\n\ + python main.py \\\n\ + --browser-args "--no-sandbox --disable-dev-shm-usage --disable-setuid-sandbox --disable-software-rasterizer"\n\ + exec "$@"' > /workspaceFolder/entrypoint.sh && chmod +x /workspaceFolder/entrypoint.sh + +HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \ + CMD xvfb-run --auto-servernum echo "Xvfb is working!" || exit 1 RUN chmod +x /workspaceFolder/entrypoint.sh ENTRYPOINT [ "/workspaceFolder/entrypoint.sh" ] From d974be4def331e70abd16940cbc53303222a61e0 Mon Sep 17 00:00:00 2001 From: 0x78f1935 Date: Wed, 23 Apr 2025 18:15:36 +0200 Subject: [PATCH 13/18] ADD: Ability to remotely connect with the virtual display --- .docker/services/turnstile/entrypoint.sh | 31 ++++++++++++++++ .docker/services/turnstile/solver.Dockerfile | 38 +++++++++++++++----- docker-compose.yaml | 1 + 3 files changed, 61 insertions(+), 9 deletions(-) create mode 100644 .docker/services/turnstile/entrypoint.sh diff --git a/.docker/services/turnstile/entrypoint.sh b/.docker/services/turnstile/entrypoint.sh new file mode 100644 index 0000000..1757921 --- /dev/null +++ b/.docker/services/turnstile/entrypoint.sh @@ -0,0 +1,31 @@ +#!/bin/bash + +# Start Xvfb +Xvfb :99 -screen 0 1024x768x16 & +XVFB_PID=$! + +# Wait for Xvfb to become ready +for i in {1..10}; do + if xdpyinfo -display :99 >/dev/null 2>&1; then + echo "Xvfb is ready!" + break + fi + echo "Waiting for Xvfb to start..." + sleep 1 +done + +# If it's not ready after 10s, bail +if ! xdpyinfo -display :99 >/dev/null 2>&1; then + echo "Xvfb did not start!" + exit 1 +fi + +# Start window manager +fluxbox & + +# Start VNC server +x11vnc -display :99 -forever -nopw -shared -listen 0.0.0.0 -rfbport 5900 -bg + +# Run your app +export DISPLAY=:99 +exec python main.py --browser-args "--no-sandbox --disable-gpu --disable-software-rasterizer --disable-dev-shm-usage --disable-setuid-sandbox --start-maximized --disable-blink-features=AutomationControlled --lang=en-US,en --window-size=1024,720 --enable-unsafe-webgpu --enable-webgl --use-gl=swiftshader --enable-features=SharedArrayBuffer,TrustTokens,PrivateNetworkAccessChecksBypassingPermissionPolicy" diff --git a/.docker/services/turnstile/solver.Dockerfile b/.docker/services/turnstile/solver.Dockerfile index 953ea22..196bccc 100644 --- a/.docker/services/turnstile/solver.Dockerfile +++ b/.docker/services/turnstile/solver.Dockerfile @@ -2,9 +2,17 @@ FROM python:3.13.3 # Prevent interactive prompts during package installs ENV DEBIAN_FRONTEND=noninteractive +ENV DISPLAY=:99 -# Install xvfb -RUN apt-get update && apt-get install -y xvfb x11-apps +# Install xvfb and VNC server +RUN apt-get update && apt-get install -y \ + xvfb \ + fluxbox \ + x11vnc \ + supervisor \ + x11-utils \ + --no-install-recommends \ + && apt-get clean && rm -rf /var/lib/apt/lists/* # Install requirements RUN pip install patchright && \ @@ -16,14 +24,26 @@ RUN pip install -r requirements.txt RUN pip install . WORKDIR /workspaceFolder/src/turnstile_solver -RUN echo '#!/bin/bash\n\ - xvfb-run --auto-servernum --server-args="-screen 0 1024x720x24" \\\n\ - python main.py \\\n\ - --browser-args "--no-sandbox --disable-dev-shm-usage --disable-setuid-sandbox --disable-software-rasterizer"\n\ - exec "$@"' > /workspaceFolder/entrypoint.sh && chmod +x /workspaceFolder/entrypoint.sh +# RUN echo '#!/bin/bash\n\ +# # Start Xvfb (virtual display) \\\n\ +# Xvfb :99 -screen 0 1024x768x16 & \\\n\ +# # Start window manager \\\n\ +# fluxbox & \\\n\ +# # Start VNC server \\\n\ +# # x11vnc -display :99 -forever -nopw -shared -bg \\\n\ +# x11vnc -display :99 -forever -nopw -shared -listen 0.0.0.0 -rfbport 5900 -bg \\\n\ +# # Export DISPLAY for Playwright to use \\\n\ +# export DISPLAY=:99 \\\n\ +# # Start resolver \\\n\ +# python main.py \\\n\ +# --browser-args "--no-sandbox --disable-gpu --disable-software-rasterizer --disable-dev-shm-usage --disable-setuid-sandbox --start-maximized --disable-blink-features=AutomationControlled --lang=en-US,en --window-size=1024,720 --enable-unsafe-webgpu --enable-webgl --use-gl=swiftshader --enable-features=SharedArrayBuffer,TrustTokens,PrivateNetworkAccessChecksBypassingPermissionPolicy"\n\ +# exec "$@"' > /workspaceFolder/entrypoint.sh && chmod +x /workspaceFolder/entrypoint.sh HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \ CMD xvfb-run --auto-servernum echo "Xvfb is working!" || exit 1 -RUN chmod +x /workspaceFolder/entrypoint.sh -ENTRYPOINT [ "/workspaceFolder/entrypoint.sh" ] +# VNC port +EXPOSE 5900 + +RUN chmod +x /workspaceFolder/.docker/services/turnstile/entrypoint.sh +ENTRYPOINT [ "/workspaceFolder/.docker/services/turnstile/entrypoint.sh" ] diff --git a/docker-compose.yaml b/docker-compose.yaml index b29d639..e8e1af0 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -9,6 +9,7 @@ services: restart: always ports: - 8088:8088 + - 5900:5900 networks: - solver From 3d0ec00077cbf8ac9b8baabc3edadfa83e207c62 Mon Sep 17 00:00:00 2001 From: 0x78f1935 Date: Wed, 23 Apr 2025 18:16:02 +0200 Subject: [PATCH 14/18] ADD: Flags which force the browser to use SwiftShader --- src/turnstile_solver/solver.py | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/turnstile_solver/solver.py b/src/turnstile_solver/solver.py index e29ec73..bc7d7cb 100644 --- a/src/turnstile_solver/solver.py +++ b/src/turnstile_solver/solver.py @@ -16,15 +16,10 @@ logger = logging.getLogger(__name__) BROWSER_ARGS = { - "--disable-blink-features=AutomationControlled", # avoid navigator.webdriver detection - "--no-sandbox", - "--disable-setuid-sandbox", - "--disable-dev-shm-usage", "--disable-background-networking", "--disable-background-timer-throttling", "--disable-backgrounding-occluded-windows", "--disable-renderer-backgrounding", - "--disable-software-rasterizer", '--disable-application-cache', '--disable-field-trial-config', '--export-tagged-pdf', @@ -66,6 +61,21 @@ '--log-level=3', '--proxy-bypass-list=<-loopback>;localhost;127.0.0.1;*.local', + # Run the browser with SwiftShader and force it to accept software rendering + '--no-sandbox', + '--disable-gpu', + '--disable-software-rasterizer', + '--disable-dev-shm-usage', + '--disable-blink-features=AutomationControlled', # avoid navigator.webdriver detection + '--disable-setuid-sandbox', + '--lang=en-US,en', + '--start-maximized', + '--window-size=1024,720', + '--enable-unsafe-webgpu', + '--enable-webgl', + '--use-gl=swiftshader', + '--enable-features=SharedArrayBuffer,TrustTokens,PrivateNetworkAccessChecksBypassingPermissionPolicy', + # Not needed, here just for reference # Network/Connection Tuning # '--enable-features=NetworkService,ParallelDownloading', From d33d8955a47dd381cb50f0c5a1f15e8f005ccad9 Mon Sep 17 00:00:00 2001 From: 0x78f1935 Date: Wed, 23 Apr 2025 18:31:06 +0200 Subject: [PATCH 15/18] ADD: Additional documentation for the docker environment --- .docker/README.md | 41 +++++++++++++++++++++++++++++++++++++ README.md | 52 +++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 85 insertions(+), 8 deletions(-) create mode 100644 .docker/README.md diff --git a/.docker/README.md b/.docker/README.md new file mode 100644 index 0000000..266c939 --- /dev/null +++ b/.docker/README.md @@ -0,0 +1,41 @@ +# Docker + +The docker environment has been put together by [0x78f1935](https://github.com/0x78f1935), just like this readme file. + +## Overview + +Start the environment with `docker compose up --build -d`. Once the service is running the following ports are available by default: + +| Port | Internal Port | What is it? | +| ---- | ------------- | ---------------- | +| 8088 | 8088 | Turnstile Solver | +| 5900 | 5900 | VNC Server | + +### Turnstile Solver + +Simply make your Python / Curl requests to this server as documented in the main readme. + +### VNC Server + +You can connect without a password to the VNC server, which will show you how the browser is being handled. In addition it allows you to manually manipulate the page if neceserry. Very nice for debugging. + +It also shows you that we run none-headless. + +## Internal connection + +To talk with the internal port, connect your docker environment to the `solver` network. When doing so, the dns name `captcha_resolver` should become available to you and resolves the turnstile docker IP addr. + +- Connect to `solver` network + +```sh +docker network connect solver CONTAINER +``` + +Where `CONTAINER` is your container. + +## Recommendation + +I highly recommend in production to: + +- Disable VNC port. Only use this for development purposes +- Disable Turnstile remote port, only use the internal docker network diff --git a/README.md b/README.md index 6641cf4..ab8b484 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,23 @@ Python server to automatically solve Cloudflare Turnstile CAPTCHA with an averag PD: This repository was initially created for personal use. I've adjusted it for sharing, but it might still be slightly disorganized. Feel free to contribute, open issues, and request new features. +## Table of Content + +- [Screenshots](#screenshots) +- [Install](#install) + - [Patchright](#install-patchright-patched-chromium-browser) +- [How to use](#how-to-use) + - [Run server](#run-server) + - [Global proxy](#use-global-browser-proxy) + - [Proxy parameters](#load-proxy-parameters-from-environment-variables-all-caps) + - [Proxy file](#use-a-proxy-from-file-per-browser-context) +- [Get Token](#get-token) + - [Curl](#curl) + - [Python](#python) +- [Docker Micro Service](./.docker/README.md) +- [Disclaimer](#disclaimer-️) +- [Donate](#donate) + ## Screenshots TODO: Update @@ -14,10 +31,13 @@ TODO: Update ![Browser](images/browser.png) ## Install + ```bash pip install git+https://github.com/odell0111/turnstile_solver@main ``` + ### Install Patchright patched chromium browser + ```bash patchright install chromium ``` @@ -25,6 +45,7 @@ patchright install chromium ## How to use ### Run server + ```bash solver ``` @@ -32,23 +53,29 @@ solver ```bash solver --port 8088 --secret jWRN7DH6 --browser-position --max-attempts 3 --captcha-timeout 30 --page-load-timeout 30 --reload-on-overrun ``` + #### Use global browser proxy + ```bash solver --proxy-server http://myproxy.com:3128 --proxy-username user --proxy-password pass ``` + ##### Load proxy parameters from environment variables (all caps) + ```bash solver --proxy-server MY_PROXY_SERVER --proxy-username MY_PROXY_USERNAME --proxy-password MY_PROXY_PASSWORD ``` + ##### Use a proxy from file per browser context + ```bash solver --proxies myproxies.txt ``` - ### Get token #### cURL + ```bash curl --location --request GET 'http://127.0.0.1:8088/solve' \ --header 'ngrok-skip-browser-warning: _' \ @@ -61,6 +88,7 @@ curl --location --request GET 'http://127.0.0.1:8088/solve' \ ``` #### Python + ```python import requests @@ -80,8 +108,8 @@ json_data = { } response = requests.get( - url=url, - headers=headers, + url=url, + headers=headers, json=json_data, ) @@ -100,31 +128,39 @@ print("Token:", token) ``` -## Disclaimer ‼️ +## Disclaimer ‼️ + Use this project entirely at your own risk. I hold no responsibility for any negative outcomes, including but not limited to API blocking and IP bans ## Donate -If you find my work useful and want to encourage further development, you can do so by donating -[//]: # ([![Donate](https://app.oxapay.com/media/btn/light-btn.png)](https://oxapay.com/donate/42319117)) +If you find my work useful and want to encourage further development, you can do so by donating -[//]: # ( ) +[//]: # '[![Donate](https://app.oxapay.com/media/btn/light-btn.png)](https://oxapay.com/donate/42319117)' +[//]: # ' ' ### [OxaPay](https://oxapay.com/donate/42319117) ### TON + ``` UQCyCnWVYOmv97idVFZ4tIewToZacRhYVwfGNU658fN5w3Kl ``` + ### Bitcoin + ``` 1E9kw3FuaahfeproboNL7uvyBdjP9wY6CR ``` + ### Bitcoin (BEP20) + ``` 0x88046e6d0f2bf8629cd7fbd754e4e275083fc993 ``` + #### Speed Lightning Address username + ``` bytechanger@speed.app -``` \ No newline at end of file +``` From d5e822743e8fa3fa9bfe5c86d8945327d534c0c5 Mon Sep 17 00:00:00 2001 From: 0x78f1935 Date: Wed, 23 Apr 2025 18:33:12 +0200 Subject: [PATCH 16/18] ADD: Docstring withh recommendation --- docker-compose.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/docker-compose.yaml b/docker-compose.yaml index e8e1af0..1ffeffa 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -8,6 +8,7 @@ services: dockerfile: ./.docker/services/turnstile/solver.Dockerfile restart: always ports: + # Recommendation: Disable both ports in production - 8088:8088 - 5900:5900 networks: From c9c492c672ab3f7a3ed97735c3a4d1136a85cf8c Mon Sep 17 00:00:00 2001 From: 0x78f1935 Date: Wed, 23 Apr 2025 18:33:27 +0200 Subject: [PATCH 17/18] DELETE: Test string --- .docker/services/turnstile/solver.Dockerfile | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/.docker/services/turnstile/solver.Dockerfile b/.docker/services/turnstile/solver.Dockerfile index 196bccc..9b62d8b 100644 --- a/.docker/services/turnstile/solver.Dockerfile +++ b/.docker/services/turnstile/solver.Dockerfile @@ -24,20 +24,6 @@ RUN pip install -r requirements.txt RUN pip install . WORKDIR /workspaceFolder/src/turnstile_solver -# RUN echo '#!/bin/bash\n\ -# # Start Xvfb (virtual display) \\\n\ -# Xvfb :99 -screen 0 1024x768x16 & \\\n\ -# # Start window manager \\\n\ -# fluxbox & \\\n\ -# # Start VNC server \\\n\ -# # x11vnc -display :99 -forever -nopw -shared -bg \\\n\ -# x11vnc -display :99 -forever -nopw -shared -listen 0.0.0.0 -rfbport 5900 -bg \\\n\ -# # Export DISPLAY for Playwright to use \\\n\ -# export DISPLAY=:99 \\\n\ -# # Start resolver \\\n\ -# python main.py \\\n\ -# --browser-args "--no-sandbox --disable-gpu --disable-software-rasterizer --disable-dev-shm-usage --disable-setuid-sandbox --start-maximized --disable-blink-features=AutomationControlled --lang=en-US,en --window-size=1024,720 --enable-unsafe-webgpu --enable-webgl --use-gl=swiftshader --enable-features=SharedArrayBuffer,TrustTokens,PrivateNetworkAccessChecksBypassingPermissionPolicy"\n\ -# exec "$@"' > /workspaceFolder/entrypoint.sh && chmod +x /workspaceFolder/entrypoint.sh HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \ CMD xvfb-run --auto-servernum echo "Xvfb is working!" || exit 1 From 27cbd61f06e27319786974a58afbdec14ce9db3e Mon Sep 17 00:00:00 2001 From: 0x78f1935 Date: Wed, 23 Apr 2025 19:15:33 +0200 Subject: [PATCH 18/18] FIX: Port collision --- .docker/README.md | 2 +- .docker/services/turnstile/entrypoint.sh | 2 +- .docker/services/turnstile/solver.Dockerfile | 3 --- docker-compose.yaml | 2 +- 4 files changed, 3 insertions(+), 6 deletions(-) diff --git a/.docker/README.md b/.docker/README.md index 266c939..139b396 100644 --- a/.docker/README.md +++ b/.docker/README.md @@ -9,7 +9,7 @@ Start the environment with `docker compose up --build -d`. Once the service is r | Port | Internal Port | What is it? | | ---- | ------------- | ---------------- | | 8088 | 8088 | Turnstile Solver | -| 5900 | 5900 | VNC Server | +| 5901 | 5901 | VNC Server | ### Turnstile Solver diff --git a/.docker/services/turnstile/entrypoint.sh b/.docker/services/turnstile/entrypoint.sh index 1757921..8e78b84 100644 --- a/.docker/services/turnstile/entrypoint.sh +++ b/.docker/services/turnstile/entrypoint.sh @@ -24,7 +24,7 @@ fi fluxbox & # Start VNC server -x11vnc -display :99 -forever -nopw -shared -listen 0.0.0.0 -rfbport 5900 -bg +x11vnc -display :99 -forever -nopw -shared -listen 0.0.0.0 -rfbport 5901 -bg # Run your app export DISPLAY=:99 diff --git a/.docker/services/turnstile/solver.Dockerfile b/.docker/services/turnstile/solver.Dockerfile index 9b62d8b..2ded5b5 100644 --- a/.docker/services/turnstile/solver.Dockerfile +++ b/.docker/services/turnstile/solver.Dockerfile @@ -28,8 +28,5 @@ WORKDIR /workspaceFolder/src/turnstile_solver HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \ CMD xvfb-run --auto-servernum echo "Xvfb is working!" || exit 1 -# VNC port -EXPOSE 5900 - RUN chmod +x /workspaceFolder/.docker/services/turnstile/entrypoint.sh ENTRYPOINT [ "/workspaceFolder/.docker/services/turnstile/entrypoint.sh" ] diff --git a/docker-compose.yaml b/docker-compose.yaml index 1ffeffa..e97d928 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -10,7 +10,7 @@ services: ports: # Recommendation: Disable both ports in production - 8088:8088 - - 5900:5900 + - 5901:5901 networks: - solver