mirror of
https://github.com/dgtlmoon/changedetection.io.git
synced 2026-10-26 00:28:42 +00:00
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.
33 lines
1.2 KiB
Python
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}"
|