"""Tests for the SOCKS5 proxy HTTP/TCP module.""" import ssl import urllib.request from unittest.mock import MagicMock, patch import socks from socks import SOCKS5 from derp.http import ( _PROXY_ADDR, _PROXY_PORT, _ProxyHandler, build_opener, create_connection, ) class TestProxyHandler: def test_uses_socks5(self): handler = _ProxyHandler() assert handler.args[0] == SOCKS5 def test_proxy_address(self): handler = _ProxyHandler() assert handler.args[1] == _PROXY_ADDR assert handler.args[2] == _PROXY_PORT def test_rdns_enabled(self): handler = _ProxyHandler() assert handler.args[3] is True def test_default_ssl_context(self): handler = _ProxyHandler() assert isinstance(handler._ssl_context, ssl.SSLContext) def test_custom_ssl_context(self): ctx = ssl.create_default_context() ctx.check_hostname = False handler = _ProxyHandler(context=ctx) assert handler._ssl_context is ctx def test_is_https_handler(self): handler = _ProxyHandler() assert isinstance(handler, urllib.request.HTTPSHandler) class TestBuildOpener: def test_includes_proxy_handler(self): opener = build_opener() proxy = [h for h in opener.handlers if isinstance(h, _ProxyHandler)] assert len(proxy) == 1 def test_passes_extra_handlers(self): class Custom(urllib.request.HTTPRedirectHandler): pass opener = build_opener(Custom) custom = [h for h in opener.handlers if isinstance(h, Custom)] assert len(custom) == 1 def test_passes_ssl_context(self): ctx = ssl.create_default_context() ctx.check_hostname = False opener = build_opener(context=ctx) proxy = [h for h in opener.handlers if isinstance(h, _ProxyHandler)][0] assert proxy._ssl_context is ctx class TestCreateConnection: @patch("derp.http.socks.socksocket") def test_sets_socks5_proxy(self, mock_cls): sock = MagicMock() mock_cls.return_value = sock create_connection(("example.com", 443), timeout=5) sock.set_proxy.assert_called_once_with( SOCKS5, _PROXY_ADDR, _PROXY_PORT, rdns=True, ) @patch("derp.http.socks.socksocket") def test_connects_to_target(self, mock_cls): sock = MagicMock() mock_cls.return_value = sock create_connection(("example.com", 443)) sock.connect.assert_called_once_with(("example.com", 443)) @patch("derp.http.socks.socksocket") def test_sets_timeout(self, mock_cls): sock = MagicMock() mock_cls.return_value = sock create_connection(("example.com", 80), timeout=7) sock.settimeout.assert_called_once_with(7) @patch("derp.http.socks.socksocket") def test_no_timeout_when_none(self, mock_cls): sock = MagicMock() mock_cls.return_value = sock create_connection(("example.com", 80)) sock.settimeout.assert_not_called() @patch("derp.http.socks.socksocket") def test_returns_socket(self, mock_cls): sock = MagicMock() mock_cls.return_value = sock result = create_connection(("example.com", 443)) assert result is sock