Files
changedetection.io/changedetectionio/proxy_url.py
T
Alexandr Kazmin 04bcf5ea5a Decode proxy credentials for browser fetchers and redact them in logs (#4502)
Proxy usernames and passwords with special characters have to be URL-escaped
(#2062). The requests fetcher decodes them, but the Playwright and Puppeteer
fetchers and Browser Steps passed the escaped values to the browser as-is.

The proxy URL, password included, was also logged at DEBUG, the default level.

Add proxy_credentials() and redact_proxy_url() in changedetectionio/proxy_url.py
and use them at those sites, with unit tests.
2026-10-23 12:01:23 +02:00

33 lines
1.2 KiB
Python

"""
Helpers for proxy URLs that carry credentials.
A username or password containing characters such as `#`, `/`, `?` or `@` has to
be percent-encoded in the URL, otherwise the URL does not parse. Browser fetchers
take the username and password as separate fields, so they need the decoded
values. Anything written to the log gets the credentials removed.
"""
from urllib.parse import unquote, urlparse
def proxy_credentials(proxy_url):
"""Return the decoded (username, password) of a proxy URL, either may be None."""
if not proxy_url:
return None, None
parsed = urlparse(proxy_url)
username = unquote(parsed.username) if parsed.username is not None else None
password = unquote(parsed.password) if parsed.password is not None else None
return username, password
def redact_proxy_url(proxy_url):
"""The proxy URL with its username and password replaced by `***`, for logging."""
if not proxy_url or '@' not in proxy_url:
return proxy_url
scheme, separator, rest = proxy_url.partition('://')
if not separator:
scheme, rest = '', proxy_url
# rpartition: an unencoded `@` or `#` in the password must not leave part of it behind
host = rest.rpartition('@')[2]
return f"{scheme}{separator}***@{host}"