feat: route plugin HTTP traffic through SOCKS5 proxy
Add PySocks dependency and shared src/derp/http.py module providing proxy-aware urlopen() and build_opener() that route through socks5h://127.0.0.1:1080. Subclassed SocksiPyHandler passes SSL context through to HTTPS connections. Swapped 14 external-facing plugins to use the proxied helpers. Local-only traffic (SearXNG, raw DNS/TLS sockets) stays direct. Updated test mocks in test_twitch and test_alert accordingly.
This commit is contained in:
48
src/derp/http.py
Normal file
48
src/derp/http.py
Normal file
@@ -0,0 +1,48 @@
|
||||
"""Proxy-aware HTTP helpers -- routes outbound traffic through SOCKS5."""
|
||||
|
||||
import socket
|
||||
import ssl
|
||||
import urllib.request
|
||||
|
||||
from socks import SOCKS5
|
||||
from sockshandler import SocksiPyConnectionS, SocksiPyHandler
|
||||
|
||||
_PROXY_ADDR = "127.0.0.1"
|
||||
_PROXY_PORT = 1080
|
||||
|
||||
|
||||
class _ProxyHandler(SocksiPyHandler, urllib.request.HTTPSHandler):
|
||||
"""SOCKS5 handler that forwards SSL context to HTTPS connections."""
|
||||
|
||||
def __init__(self, context=None):
|
||||
self._ssl_context = context or ssl.create_default_context()
|
||||
SocksiPyHandler.__init__(self, SOCKS5, _PROXY_ADDR, _PROXY_PORT, True)
|
||||
|
||||
def https_open(self, req):
|
||||
"""Open HTTPS connection through SOCKS5 with SSL context."""
|
||||
ctx = self._ssl_context
|
||||
|
||||
def build(host, port=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT, **kwargs):
|
||||
conn = SocksiPyConnectionS(
|
||||
*self.args, host=host, port=port, context=ctx, **self.kw,
|
||||
)
|
||||
conn.timeout = timeout
|
||||
return conn
|
||||
|
||||
return self.do_open(build, req)
|
||||
|
||||
|
||||
def urlopen(req, *, timeout=None, context=None):
|
||||
"""Proxy-aware drop-in for urllib.request.urlopen."""
|
||||
handler = _ProxyHandler(context=context)
|
||||
opener = urllib.request.build_opener(handler)
|
||||
kwargs = {}
|
||||
if timeout is not None:
|
||||
kwargs["timeout"] = timeout
|
||||
return opener.open(req, **kwargs)
|
||||
|
||||
|
||||
def build_opener(*handlers, context=None):
|
||||
"""Proxy-aware drop-in for urllib.request.build_opener."""
|
||||
proxy = _ProxyHandler(context=context)
|
||||
return urllib.request.build_opener(proxy, *handlers)
|
||||
Reference in New Issue
Block a user