Skip to content

Accept the dashboard's host:port:login:password proxy; refuse a gateway URL with no login - #6

Merged
jehrr merged 1 commit into
mainfrom
fix/proxy-without-login-2026-10-16
Oct 16, 2026
Merged

jehrr merged 1 commit into
mainfrom
fix/proxy-without-login-2026-10-16

Conversation

@jehrr

@jehrr jehrr commented Oct 16, 2026

Copy link
Copy Markdown
Collaborator

Problem

tools/browser_profile_client.py connection --mint-session (the canary's "Build a fresh endpoint" step) died twice with "--proxy-sessions only applies to a 2Captcha proxy gateway … the URL given is not one". Two inputs reach that path:

  • The dashboard's colon form, host:port:login:password (with or without http://). Read as a URL it has no username and a "port" of port:login:password, so a gateway credential looked like an IP-whitelisted one. urlparse's ValueError on that port quotes the login.
  • A gateway URL with no login (http://HOST:PORT, http://:pw@HOST:PORT). minted_proxy rebuilt the URL with base.replace(parts.username or "", login, 1). With an empty username that puts the login in front of http://, so the rebuilt URL has no host and the error blames the host.

Behaviour now

  • proxy_pool.normalize_proxy rewrites the colon form to scheme://login:password@host:port. The scheme defaults to http, and the login and password are percent-encoded. It runs in parse_proxy_line (covering --proxy and --proxy-file), is_2captcha_gateway, mask, browser_bridge.parse_args (once, for every engine and the solver) and the browser-profile tool.
  • Every consumer decodes the login and password before using them: Playwright's proxy dict, split_credentials, pyppeteer authenticate, the local forwarder's Proxy-Authorization, the solver's proxyLogin/proxyPassword and the profile tool's customProxy. That way a password containing @ : / % # arrives intact.
  • require_gateway_login refuses a gateway URL that lacks a login and password, with "AVITO_PROXY has no login: session minting needs the gateway's LOGIN:PASSWORD form (…); an IP-whitelisted gateway URL cannot carry a -session-/-sessTime- id." The message never contains the credential. The tool exits 1; the scrapers exit 2 (argparse) when they would pin a session.
  • The login is replaced inside the netloc (with_login, which rebuilds the URL from its parts) and no longer by a str.replace on the whole URL. A port that will not parse raises a ProxyError built from the masked value.
  • README (AVITO_PROXY section) documents both accepted forms and the refusal. .env.example comment updated. CHANGELOG [Unreleased].

Evidence

Python 3.13 core-only venv (requirements.txt + pytest):

  • smoke_test.py: 684 checks, 0 failed, 6 skipped (engines absent). pytest -q: 94 passed.
  • ci_checks.py --help-check, --sample-check, --secret-check, --wheel-check: all exit 0. env_config.py and compileall: 0.
  • pyppeteer venv (requirements-puppeteer.txt, no browser download): 699 checks, 0 failed; the pyppeteer argv guards ran. puppeteer_scraper.py --help: 0.

New offline checks cover host-only, empty username, login without password, three colon fields, a plain login, a login already carrying -session-/-sessTime-, socks5, a %-encoded password, and the colon form bare, with http:// and with @ : / % # in the password. Each case goes through minted_proxy, mint_sessions, parse_proxy_line, to_playwright, proxy_task_fields, the forwarder and parse_args. They also assert that no message contains the credential.

Planted-fault controls (with PYTHONDONTWRITEBYTECODE=1 and __pycache__ cleared):

  • old proxy_pool.py + old browser_profile_client.py → 20 failed. The old code reproduces "the URL given is not one", and the old ValueError quotes the login.
  • new proxy_pool.py + old browser_profile_client.py → 16 failed. All are minted_proxy checks, including host -sesstime-60ru.proxy.2captcha.com from the old str.replace.
  • old captcha_solver.py → "solver fields decoded" fails (password sent still encoded).
  • old proxy_forwarder.py → "the forwarder sends the decoded credential" fails.
  • restored → green.

No paid calls, proxies or credentials were used, and nothing was sent to any 2Captcha endpoint.

Not changed

Canary policy, versions/releases, and the rest of the session-minting design.

🤖 Generated with Claude Code

https://claude.ai/code/session_01CKsd7q25N19WzUZjrAdzx8

…ay URL with no login

AVITO_PROXY / --proxy / --proxy-file lines in the 2Captcha dashboard's
colon form (with or without http://) are now normalised to
scheme://login:password@host:port, login and password percent-encoded and
decoded again before Playwright, pyppeteer, the forwarder and the solver
see them. A gateway URL without a login and password is refused by name
when a session must be minted or pinned, instead of a login being spliced
in front of the scheme and the run dying with "not a 2Captcha gateway".
The login is now replaced inside the netloc, and no message built from a
proxy value repeats the credential.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CKsd7q25N19WzUZjrAdzx8
@jehrr
jehrr merged commit 6868885 into main Oct 16, 2026
7 checks passed
@jehrr jehrr mentioned this pull request Oct 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant