import json import unittest from sbp.config import build_client_config, build_server_config from sbp.errors import SbpError from sbp.share import all_uris, share_uri from tests.test_state import CERT_SHA256, SERVER_SS_KEY, USER_SS_KEY, sample_state class ServerConfigTest(unittest.TestCase): def setUp(self) -> None: self.state = sample_state() self.config = build_server_config(self.state) def test_all_protocols_present(self) -> None: tags = {inbound["tag"] for inbound in self.config["inbounds"]} self.assertEqual( tags, {"hysteria2-in", "vless-reality-in", "trojan-in", "shadowsocks-in", "tuic-in", "anytls-in"}, ) def test_disabled_protocol_is_skipped(self) -> None: self.state.protocols["trojan"].enabled = False tags = {inbound["tag"] for inbound in build_server_config(self.state)["inbounds"]} self.assertNotIn("trojan-in", tags) def test_hysteria2_tls_and_obfs(self) -> None: inbound = next(i for i in self.config["inbounds"] if i["tag"] == "hysteria2-in") self.assertEqual(inbound["tls"]["alpn"], ["h3"]) self.assertEqual(inbound["obfs"]["type"], "salamander") self.assertEqual(inbound["users"][0]["password"], "PASSWORD") def test_reality_uses_private_key(self) -> None: inbound = next(i for i in self.config["inbounds"] if i["tag"] == "vless-reality-in") self.assertEqual(inbound["tls"]["reality"]["private_key"], "PRIVATE") self.assertEqual(inbound["tls"]["reality"]["handshake"]["server"], "www.bing.com") def test_shadowsocks_multi_user(self) -> None: inbound = next(i for i in self.config["inbounds"] if i["tag"] == "shadowsocks-in") self.assertEqual(inbound["password"], SERVER_SS_KEY) self.assertEqual(inbound["users"][0]["password"], USER_SS_KEY) def test_shadowsocks_client_sends_identity_and_user_key(self) -> None: config = build_client_config(self.state, "shadowsocks", self.state.users[0]) self.assertEqual( config["outbounds"][0]["password"], f"{SERVER_SS_KEY}:{USER_SS_KEY}" ) def test_config_is_json_serializable(self) -> None: json.dumps(self.config) def test_reality_rejects_ip_server_name(self) -> None: self.state.protocols["vless-reality"].options["server_name"] = "203.0.113.10" with self.assertRaises(SbpError): build_server_config(self.state) def test_reality_rejects_odd_length_short_id(self) -> None: self.state.protocols["vless-reality"].options["short_id"] = "abc" with self.assertRaises(SbpError): build_server_config(self.state) def test_reality_accepts_even_short_id(self) -> None: self.state.protocols["vless-reality"].options["short_id"] = "ab12" build_server_config(self.state) class ClientConfigTest(unittest.TestCase): def setUp(self) -> None: self.state = sample_state() self.user = self.state.users[0] def test_disabled_protocol_raises_sbp_error(self) -> None: self.state.protocols["tuic"].enabled = False with self.assertRaises(SbpError): build_client_config(self.state, "tuic", self.user) with self.assertRaises(SbpError): share_uri(self.state, "tuic", self.user) def test_each_client_config_routes_to_outbound(self) -> None: for key in self.state.protocols: config = build_client_config(self.state, key, self.user) self.assertEqual(config["route"]["final"], config["outbounds"][0]["tag"]) json.dumps(config) def test_self_signed_pins_public_key(self) -> None: config = build_client_config(self.state, "trojan", self.user) self.assertEqual( config["outbounds"][0]["tls"]["certificate_public_key_sha256"], ["SPKI"] ) def test_reality_does_not_pin(self) -> None: config = build_client_config(self.state, "vless-reality", self.user) tls = config["outbounds"][0]["tls"] self.assertNotIn("certificate_public_key_sha256", tls) self.assertEqual(tls["reality"]["public_key"], "PUBLIC") class ShareUriTest(unittest.TestCase): def setUp(self) -> None: self.state = sample_state() self.user = self.state.users[0] def test_uri_prefixes(self) -> None: prefixes = { "hysteria2": "hysteria2://", "vless-reality": "vless://", "trojan": "trojan://", "shadowsocks": "ss://", "tuic": "tuic://", "anytls": "anytls://", } for key, prefix in prefixes.items(): self.assertTrue(share_uri(self.state, key, self.user).startswith(prefix), key) def test_hysteria2_pin_and_obfs(self) -> None: uri = share_uri(self.state, "hysteria2", self.user) self.assertIn(f"pinSHA256={CERT_SHA256}", uri) self.assertIn("obfs=salamander", uri) def test_vless_reality_parameters(self) -> None: uri = share_uri(self.state, "vless-reality", self.user) self.assertIn("security=reality", uri) self.assertIn("pbk=PUBLIC", uri) self.assertIn("flow=xtls-rprx-vision", uri) def test_shadowsocks_uses_plain_userinfo(self) -> None: from urllib.parse import unquote uri = share_uri(self.state, "shadowsocks", self.user) userinfo = unquote(uri.removeprefix("ss://").split("@", 1)[0]) self.assertEqual(userinfo, f"2022-blake3-aes-128-gcm:{SERVER_SS_KEY}:{USER_SS_KEY}") def test_all_uris(self) -> None: self.assertEqual(len(all_uris(self.state, self.user)), 6) if __name__ == "__main__": unittest.main()