Files
singbox_glue/tests/test_uri.py
T

106 lines
4.8 KiB
Python

from __future__ import annotations
import unittest
from vpn_egressctl.errors import ValidationError
from vpn_egressctl.uri import parse_hysteria2_uri
class UriParserTests(unittest.TestCase):
def test_minimal_uri(self) -> None:
endpoint = parse_hysteria2_uri("hysteria2://secret@example.com/")
self.assertEqual(endpoint.server, "example.com")
self.assertEqual(endpoint.server_port, 443)
self.assertEqual(endpoint.password, "secret")
self.assertEqual(endpoint.sni, "example.com")
def test_short_scheme_and_percent_encoding(self) -> None:
endpoint = parse_hysteria2_uri("hy2://user%3Apass@EXAMPLE.com:8443?sni=t%C3%A9st.example#Moscow")
self.assertEqual(endpoint.password, "user:pass")
self.assertEqual(endpoint.server, "example.com")
self.assertEqual(endpoint.server_port, 8443)
self.assertEqual(endpoint.sni, "xn--tst-bma.example")
self.assertEqual(endpoint.display_name, "Moscow")
def test_salamander(self) -> None:
endpoint = parse_hysteria2_uri(
"hysteria2://secret@example.com:443/?insecure=1&obfs=salamander&obfs-password=o%40p"
)
self.assertTrue(endpoint.insecure)
self.assertEqual(endpoint.obfs_type, "salamander")
self.assertEqual(endpoint.obfs_password, "o@p")
def test_ipv6(self) -> None:
endpoint = parse_hysteria2_uri("hysteria2://secret@[2001:db8::1]:444/")
self.assertEqual(endpoint.server, "2001:db8::1")
self.assertEqual(endpoint.server_port, 444)
self.assertEqual(endpoint.endpoint_label(), "[2001:db8::1]:444")
def test_multi_port(self) -> None:
endpoint = parse_hysteria2_uri("hysteria2://secret@example.com:443,5000-6000/")
self.assertIsNone(endpoint.server_port)
self.assertEqual(endpoint.server_ports, ("443", "5000:6000"))
def test_range_only_uses_server_ports(self) -> None:
endpoint = parse_hysteria2_uri("hysteria2://secret@example.com:5000-6000/")
self.assertIsNone(endpoint.server_port)
self.assertEqual(endpoint.server_ports, ("5000:6000",))
def test_userpass_is_preserved(self) -> None:
endpoint = parse_hysteria2_uri("hysteria2://alice%3Acorrect%20horse@example.com")
self.assertEqual(endpoint.password, "alice:correct horse")
def test_percent_encoded_at_is_preserved(self) -> None:
endpoint = parse_hysteria2_uri("hysteria2://alice%40example@example.com")
self.assertEqual(endpoint.password, "alice@example")
def test_unicode_host_is_idna(self) -> None:
endpoint = parse_hysteria2_uri("hysteria2://secret@пример.рф")
self.assertEqual(endpoint.server, "xn--e1afmkfd.xn--p1ai")
def test_repr_hides_secrets(self) -> None:
endpoint = parse_hysteria2_uri(
"hysteria2://TOPSECRET@example.com?obfs=salamander&obfs-password=OBFSSECRET"
)
text = repr(endpoint)
self.assertNotIn("TOPSECRET", text)
self.assertNotIn("OBFSSECRET", text)
def assert_invalid(self, uri: str, marker: str | None = None) -> None:
with self.assertRaises(ValidationError) as caught:
parse_hysteria2_uri(uri)
if marker:
self.assertIn(marker, str(caught.exception))
def test_rejections(self) -> None:
cases = [
("http://secret@example.com", "scheme"),
("hysteria2://example.com", "authentication"),
("hysteria2://@example.com", "authentication"),
("hysteria2://secret@", "server"),
("hysteria2://secret@example.com:0", "1..65535"),
("hysteria2://secret@example.com:65536", "1..65535"),
("hysteria2://secret@example.com:100-99", "range"),
("hysteria2://secret@example.com:100,100", "Overlapping"),
("hysteria2://secret@2001:db8::1", "brackets"),
("hysteria2://secret@example.com/path", "paths"),
("hysteria2://secret@example.com?unknown=x", "Unsupported"),
("hysteria2://secret@example.com?sni=a&sni=b", "Duplicate"),
("hysteria2://secret@example.com?insecure=true", "exactly"),
("hysteria2://secret@example.com?obfs=gecko", "1.13.19"),
("hysteria2://secret@example.com?obfs=salamander", "obfs-password"),
("hysteria2://secret@example.com?obfs-password=x", "requires"),
("hysteria2://secret@example.com?pinSHA256=x", "safely"),
("hysteria2://secret@example.com?ech=x", "safely"),
("hysteria2://sec%ZZret@example.com", "percent"),
("hysteria2://alice@example@server.example", "percent-encoded"),
("hysteria2://secret@example.com?sni=%FF", "UTF-8"),
]
for uri, marker in cases:
with self.subTest(uri=uri):
self.assert_invalid(uri, marker)
if __name__ == "__main__":
unittest.main()