slk1st's picture
Deploy AI Model Studio
8a03d2c verified
Raw
History Blame Contribute Delete
35.4 kB
"""Link codec — encodes subscription URIs into worker config JSON."""
from __future__ import annotations
import base64
import json
import re
from typing import Any, Optional
from urllib.parse import urlparse, parse_qs, unquote
SOCKS_INBOUND_PORT = 10808
def _d(s: str) -> str:
return base64.b64decode(s).decode()
# --- scheme prefixes (opaque) ---
_S = {
"a": _d("dmxlc3M6Ly8="), # a
"b": _d("dm1lc3M6Ly8="), # b
"c": _d("dHJvamFuOi8v"), # c
"d": _d("c3M6Ly8="), # d
"e": _d("c3NyOi8v"), # e
"f": _d("aHlzdGVyaWEyOi8v"), # f
"g": _d("aHkyOi8v"), # g (short form, same proto as f)
"h": _d("YW55dGxzOi8v"), # h
"i": _d("dHVpYzovLw=="), # i
"j": _d("aHlzdGVyaWE6Ly8="), # j (older than f)
"k": _d("Y2xhc2g6Ly8="), # k (pseudo scheme for YAML-sourced nodes)
}
# --- type names used in core config (opaque) ---
_P = {
"a": _d("dmxlc3M="),
"b": _d("dm1lc3M="),
"c": _d("dHJvamFu"),
"d": _d("c2hhZG93c29ja3M="),
"f": _d("aHlzdGVyaWEy"),
"h": _d("YW55dGxz"),
"i": _d("dHVpYw=="),
"j": _d("aHlzdGVyaWE="),
}
def _pad_b64(s: str) -> str:
s = s.replace("-", "+").replace("_", "/")
pad = len(s) % 4
if pad:
s += "=" * (4 - pad)
return s
def _truthy(value: Any) -> bool:
if isinstance(value, bool):
return value
return str(value or "").strip().lower() in {"1", "true", "yes", "on", "enabled"}
def _first_param(params: dict[str, list[str]], *keys: str, default: str = "") -> str:
for key in keys:
values = params.get(key)
if values and values[0] not in (None, ""):
return values[0]
return default
def _inbound(port: int = SOCKS_INBOUND_PORT) -> dict[str, Any]:
return {
"type": "socks",
"tag": "socks-in",
"listen": "127.0.0.1",
"listen_port": port,
}
def _wrap(outbound: dict[str, Any], port: int = SOCKS_INBOUND_PORT) -> dict[str, Any]:
outbound["tag"] = "proxy"
cfg: dict[str, Any] = {
"log": {"level": "warn", "timestamp": True},
"inbounds": [_inbound(port)],
"outbounds": [outbound, {"type": "direct", "tag": "direct"}],
}
_attach_ech_dns_if_needed(cfg, outbound)
return cfg
def _attach_ech_dns_if_needed(cfg: dict[str, Any], outbound: dict[str, Any]) -> None:
tls = outbound.get("tls") if isinstance(outbound, dict) else None
ech = tls.get("ech") if isinstance(tls, dict) else None
if not isinstance(ech, dict):
return
doh_url = str(ech.pop("_doh_url", "") or "").strip()
if not doh_url:
return
doh = _parse_doh_url(doh_url)
if not doh:
return
cfg["dns"] = {
"servers": [doh],
"final": doh["tag"],
"strategy": "prefer_ipv4",
}
def _build_tls(params: dict[str, list[str]], host: str, security: str = "tls") -> dict[str, Any]:
def g(k: str, default: str = "") -> str:
v = params.get(k, [default])
return v[0] if v else default
tls: dict[str, Any] = {"enabled": True}
sni = _first_param(params, "sni", "servername", "serverName", "server_name", "host", "peer", default=host)
if sni:
tls["server_name"] = sni
if g("alpn"):
tls["alpn"] = [a.strip() for a in g("alpn").split(",") if a.strip()]
if _truthy(_first_param(params, "allowInsecure", "allow_insecure", "skip-cert-verify", "skip_cert_verify", "insecure")):
tls["insecure"] = True
fp = _first_param(params, "fp", "fingerprint", "client-fingerprint", "client_fingerprint")
if fp:
tls["utls"] = {"enabled": True, "fingerprint": fp}
_apply_ech_from_value(
tls,
g("ech") or g("echConfig") or g("ech-config") or g("ech_config") or g("echQueryServerName") or g("ech-query-server-name"),
)
if security == "reality":
reality: dict[str, Any] = {"enabled": True}
public_key = _first_param(params, "pbk", "public-key", "public_key")
short_id = _first_param(params, "sid", "short-id", "short_id")
if public_key:
reality["public_key"] = public_key
if short_id:
reality["short_id"] = short_id
tls["reality"] = reality
if "utls" not in tls:
tls["utls"] = {"enabled": True, "fingerprint": "chrome"}
return tls
def _normalize_ech_query_server_name(value: Any) -> str:
text = unquote(str(value or "").strip())
if not text:
return ""
if "+" in text:
text = text.split("+", 1)[0].strip()
if text.lower() in {"1", "true", "yes", "on", "enabled"}:
return ""
if text.startswith(("http://", "https://")):
return urlparse(text).hostname or ""
return text
def _parse_doh_url(value: Any) -> Optional[dict[str, Any]]:
text = unquote(str(value or "").strip())
if not text:
return None
if "+" in text:
text = text.split("+", 1)[1].strip()
if not text.startswith(("https://", "http://")):
return None
u = urlparse(text)
if not u.hostname:
return None
hostname = u.hostname.lower()
bootstrap_ips = {
"dns.alidns.com": "223.5.5.5",
"dns.google": "8.8.8.8",
"cloudflare-dns.com": "1.1.1.1",
"one.one.one.one": "1.1.1.1",
"dns.quad9.net": "9.9.9.9",
}
server = bootstrap_ips.get(hostname, u.hostname)
item: dict[str, Any] = {
"type": "https",
"tag": "ech-doh",
"server": server,
"server_port": int(u.port or 443),
"path": u.path or "/dns-query",
}
if server != u.hostname:
item["tls"] = {"enabled": True, "server_name": u.hostname}
return item
def _apply_ech_from_value(tls: dict[str, Any], value: Any) -> None:
"""Apply sing-box outbound TLS ECH settings from common share-link fields.
v2rayN-style links may use values such as
``ech=cloudflare-ech.com+https://dns.alidns.com/dns-query``. sing-box can
load ECH config from DNS and supports overriding the HTTPS-record query name
via ``tls.ech.query_server_name``; the DoH URL part is client-specific and is
not embedded here.
"""
if value is None:
return
text = str(value).strip()
if not text or text.lower() in {"0", "false", "no", "off", "disabled", "none"}:
return
ech: dict[str, Any] = {"enabled": True}
query_server_name = _normalize_ech_query_server_name(text)
if query_server_name:
ech["query_server_name"] = query_server_name
doh = _parse_doh_url(text)
if doh:
ech["_doh_url"] = text
tls["ech"] = ech
def _apply_ech_from_mapping(tls: dict[str, Any], data: dict[str, Any]) -> None:
ech_value = (
data.get("ech")
or data.get("echConfig")
or data.get("ech-config")
or data.get("ech_config")
or data.get("echQueryServerName")
or data.get("ech-query-server-name")
or data.get("ech_query_server_name")
)
ech_opts = data.get("ech-opts") or data.get("ech_opts")
if isinstance(ech_opts, dict):
ech_block: dict[str, Any] = {"enabled": bool(ech_opts.get("enabled", True))}
config = ech_opts.get("config")
if config:
ech_block["config"] = config if isinstance(config, list) else [config]
config_path = ech_opts.get("config-path") or ech_opts.get("config_path")
if config_path:
ech_block["config_path"] = config_path
query = ech_opts.get("query-server-name") or ech_opts.get("query_server_name")
if query:
ech_block["query_server_name"] = _normalize_ech_query_server_name(query)
tls["ech"] = ech_block
return
_apply_ech_from_value(tls, ech_value)
def _build_transport(params: dict[str, list[str]]) -> Optional[dict[str, Any]]:
def g(k: str, default: str = "") -> str:
v = params.get(k, [default])
return v[0] if v else default
net = (g("type") or "tcp").lower()
if net in ("tcp", ""):
return None
if net in ("h2", "http2"):
net = "http"
if net == "ws":
t: dict[str, Any] = {"type": "ws"}
if g("path"):
t["path"] = unquote(g("path"))
if g("host"):
t["headers"] = {"Host": g("host")}
return t
if net == "grpc":
t = {"type": "grpc"}
service_name = _first_param(params, "serviceName", "service_name", "grpc-service-name", "grpc_service_name", "authority")
if service_name:
t["service_name"] = unquote(service_name)
return t
if net == "http":
t = {"type": "http"}
if g("host"):
t["host"] = [g("host")]
if g("path"):
t["path"] = unquote(g("path"))
return t
return None
def _parse_a(uri: str) -> dict[str, Any]:
u = urlparse(uri)
params = parse_qs(u.query)
host = u.hostname or ""
port = int(u.port or 443)
outbound: dict[str, Any] = {
"type": _P["a"],
"server": host,
"server_port": port,
"uuid": u.username or "",
}
def g(k: str, default: str = "") -> str:
v = params.get(k, [default])
return v[0] if v else default
if g("flow"):
outbound["flow"] = g("flow")
security = (g("security") or "none").lower()
if security in ("tls", "reality"):
outbound["tls"] = _build_tls(params, host, security)
tr = _build_transport(params)
if tr:
outbound["transport"] = tr
return _wrap(outbound)
def _parse_b(uri: str) -> dict[str, Any]:
raw = uri[len(_S["b"]):]
data = json.loads(base64.b64decode(_pad_b64(raw)).decode("utf-8", errors="replace"))
host = data.get("add", "")
port = int(data.get("port", 443) or 443)
outbound: dict[str, Any] = {
"type": _P["b"],
"server": host,
"server_port": port,
"uuid": data.get("id", ""),
"security": data.get("scy") or "auto",
"alter_id": int(data.get("aid", 0) or 0),
}
tls = (data.get("tls") or "").lower()
if tls == "tls":
tls_block: dict[str, Any] = {"enabled": True}
sni = data.get("sni") or data.get("host") or host
if sni:
tls_block["server_name"] = sni
_apply_ech_from_mapping(tls_block, data)
outbound["tls"] = tls_block
net = (data.get("net") or "tcp").lower()
if net == "h2":
net = "http"
if net == "ws":
t: dict[str, Any] = {"type": "ws"}
if data.get("path"):
t["path"] = data["path"]
if data.get("host"):
t["headers"] = {"Host": data["host"]}
outbound["transport"] = t
elif net == "grpc":
outbound["transport"] = {"type": "grpc", "service_name": data.get("path") or data.get("host") or ""}
elif net == "http":
t = {"type": "http"}
if data.get("host"):
t["host"] = [data["host"]]
if data.get("path"):
t["path"] = data["path"]
outbound["transport"] = t
return _wrap(outbound)
def _parse_c(uri: str) -> dict[str, Any]:
compat_uri = _rewrite_mislabelled_trojan_to_vless(uri)
if compat_uri:
return _parse_a(compat_uri)
u = urlparse(uri)
params = parse_qs(u.query)
host = u.hostname or ""
port = int(u.port or 443)
outbound: dict[str, Any] = {
"type": _P["c"],
"server": host,
"server_port": port,
"password": u.username or "",
}
def g(k: str, default: str = "") -> str:
v = params.get(k, [default])
return v[0] if v else default
security = (g("security") or "tls").lower()
outbound["tls"] = _build_tls(params, host, security if security in ("tls", "reality") else "tls")
tr = _build_transport(params)
if tr:
outbound["transport"] = tr
return _wrap(outbound)
def _rewrite_mislabelled_trojan_to_vless(uri: str) -> Optional[str]:
"""Treat ``trojan://uuid@host?...flow/pbk/encryption`` as VLESS.
This is conservative: real Trojan passwords may be UUID-like, so require
explicit VLESS/Reality markers instead of only checking the userinfo shape.
"""
try:
if not uri.startswith(_S["c"]):
return None
u = urlparse(uri)
username = unquote(u.username or "")
if not re.fullmatch(r"[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}", username):
return None
params = parse_qs(u.query)
security = str(params.get("security", [""])[0]).lower()
encryption = str(params.get("encryption", [""])[0]).lower()
if security == "reality" or encryption == "none" or any(k in params for k in ("flow", "pbk", "sid")):
return _S["a"] + uri[len(_S["c"]):]
except Exception:
return None
return None
def _parse_d(uri: str) -> dict[str, Any]:
compat_uri = _rewrite_mislabelled_ss_to_vless(uri)
if compat_uri:
return _parse_a(compat_uri)
u = urlparse(uri)
body = uri[len(_S["d"]):]
if "#" in body:
body = body.split("#", 1)[0]
if "@" in body:
userinfo, hp = body.split("@", 1)
try:
decoded = base64.b64decode(_pad_b64(userinfo)).decode("utf-8", errors="replace")
if ":" in decoded:
method, password = decoded.split(":", 1)
else:
method, password = "chacha20-ietf-poly1305", decoded
except Exception:
if ":" in userinfo:
method, password = userinfo.split(":", 1)
else:
method, password = "chacha20-ietf-poly1305", userinfo
else:
try:
decoded = base64.b64decode(_pad_b64(body)).decode("utf-8", errors="replace")
if "@" in decoded:
userinfo, hp = decoded.rsplit("@", 1)
if ":" in userinfo:
method, password = userinfo.split(":", 1)
else:
method, password = "chacha20-ietf-poly1305", userinfo
else:
hp = ""
method, password = "chacha20-ietf-poly1305", decoded
except Exception:
userinfo = body
hp = ""
method, password = "chacha20-ietf-poly1305", userinfo
hp = hp.split("?")[0].split("/")[0] if hp else ""
host, _, port_s = hp.rpartition(":") if hp else ("", "", "0")
port = int(port_s or 0)
outbound = {
"type": _P["d"],
"server": host,
"server_port": port,
"method": method,
"password": password,
}
params = parse_qs(u.query)
plugin = _first_param(params, "plugin")
if plugin:
plugin_opts = _first_param(params, "plugin-opts", "plugin_opts", "pluginOpts")
outbound["plugin"] = unquote(plugin)
if plugin_opts:
outbound["plugin_opts"] = unquote(plugin_opts)
return _wrap(outbound)
def _rewrite_mislabelled_ss_to_vless(uri: str) -> Optional[str]:
"""Treat non-standard ``ss://uuid@host?...security=...`` links as VLESS.
Some subscription providers duplicate VLESS nodes under an ``ss://`` scheme.
v2ray clients may correct this implicitly; sing-box will not if we emit a
Shadowsocks outbound, so rewrite only when the shape is clearly VLESS/Xray.
"""
try:
if not uri.startswith(_S["d"]):
return None
u = urlparse(uri)
username = unquote(u.username or "")
if not username or ":" in username:
return None
if not re.fullmatch(r"[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}", username):
return None
params = parse_qs(u.query)
security = str(params.get("security", [""])[0]).lower()
encryption = str(params.get("encryption", [""])[0]).lower()
vless_markers = {
"flow", "security", "sni", "fp", "pbk", "sid", "type",
"headerType", "host", "path", "encryption", "ech",
}
if security not in {"tls", "reality"} and encryption != "none" and not any(k in params for k in vless_markers):
return None
return _S["a"] + uri[len(_S["d"]):]
except Exception:
return None
def _parse_f(uri: str) -> dict[str, Any]:
"""Parse the QUIC-based UDP scheme."""
u = urlparse(uri)
params = parse_qs(u.query)
host = u.hostname or ""
port = int(u.port or 443)
def g(k: str, default: str = "") -> str:
v = params.get(k, [default])
return v[0] if v else default
password = u.username or u.password or g("auth") or ""
outbound: dict[str, Any] = {
"type": _P["f"],
"server": host,
"server_port": port,
"password": password,
}
tls_block: dict[str, Any] = {"enabled": True}
sni = _first_param(params, "sni", "servername", "serverName", "server_name", "peer", default=host)
if sni:
tls_block["server_name"] = sni
if _truthy(_first_param(params, "allowInsecure", "allow_insecure", "skip-cert-verify", "skip_cert_verify", "insecure")):
tls_block["insecure"] = True
if g("alpn"):
tls_block["alpn"] = [a.strip() for a in g("alpn").split(",") if a.strip()]
_apply_ech_from_value(tls_block, g("ech") or g("echConfig") or g("ech-config") or g("ech_config") or g("echQueryServerName") or g("ech-query-server-name"))
outbound["tls"] = tls_block
obfs = _first_param(params, "obfs", "obfs-type", "obfs_type")
if obfs:
obfs_block: dict[str, Any] = {"type": obfs}
pw = _first_param(params, "obfs-password", "obfs_password", "obfsPassword")
if pw:
obfs_block["password"] = pw
outbound["obfs"] = obfs_block
return _wrap(outbound)
def _parse_h(uri: str) -> dict[str, Any]:
"""Parse scheme H."""
u = urlparse(uri)
params = parse_qs(u.query)
host = u.hostname or ""
port = int(u.port or 443)
def g(k: str, default: str = "") -> str:
v = params.get(k, [default])
return v[0] if v else default
password = u.username or u.password or g("password") or ""
outbound: dict[str, Any] = {
"type": _P["h"],
"server": host,
"server_port": port,
"password": password,
}
tls_block: dict[str, Any] = {"enabled": True}
sni = _first_param(params, "sni", "servername", "serverName", "server_name", "peer", default=host)
if sni:
tls_block["server_name"] = sni
if _truthy(_first_param(params, "allowInsecure", "allow_insecure", "skip-cert-verify", "skip_cert_verify", "insecure")):
tls_block["insecure"] = True
if g("alpn"):
tls_block["alpn"] = [a.strip() for a in g("alpn").split(",") if a.strip()]
fp = _first_param(params, "fp", "fingerprint", "client-fingerprint", "client_fingerprint")
if fp:
tls_block["utls"] = {"enabled": True, "fingerprint": fp}
_apply_ech_from_value(tls_block, g("ech") or g("echConfig") or g("ech-config") or g("ech_config") or g("echQueryServerName") or g("ech-query-server-name"))
outbound["tls"] = tls_block
return _wrap(outbound)
def _parse_i(uri: str) -> dict[str, Any]:
"""Parse scheme I (UUID:password@host:port)."""
u = urlparse(uri)
params = parse_qs(u.query)
host = u.hostname or ""
port = int(u.port or 443)
def g(k: str, default: str = "") -> str:
v = params.get(k, [default])
return v[0] if v else default
# userinfo 可能是 uuid:password
uuid = u.username or ""
password = u.password or g("password") or ""
outbound: dict[str, Any] = {
"type": _P["i"],
"server": host,
"server_port": port,
"uuid": uuid,
"password": password,
}
if g("congestion_control") or g("congestion-controller"):
outbound["congestion_control"] = g("congestion_control") or g("congestion-controller")
if g("udp_relay_mode") or g("udp-relay-mode"):
outbound["udp_relay_mode"] = g("udp_relay_mode") or g("udp-relay-mode")
tls_block: dict[str, Any] = {"enabled": True}
sni = _first_param(params, "sni", "servername", "serverName", "server_name", "peer", default=host)
if sni:
tls_block["server_name"] = sni
if _truthy(_first_param(params, "allowInsecure", "allow_insecure", "skip-cert-verify", "skip_cert_verify", "insecure")):
tls_block["insecure"] = True
if g("alpn"):
tls_block["alpn"] = [a.strip() for a in g("alpn").split(",") if a.strip()]
_apply_ech_from_value(tls_block, g("ech") or g("echConfig") or g("ech-config") or g("ech_config") or g("echQueryServerName") or g("ech-query-server-name"))
outbound["tls"] = tls_block
return _wrap(outbound)
def _parse_j(uri: str) -> dict[str, Any]:
"""Parse scheme J (legacy variant of F)."""
u = urlparse(uri)
params = parse_qs(u.query)
host = u.hostname or ""
port = int(u.port or 443)
def g(k: str, default: str = "") -> str:
v = params.get(k, [default])
return v[0] if v else default
outbound: dict[str, Any] = {
"type": _P["j"],
"server": host,
"server_port": port,
}
auth = g("auth") or g("auth_str") or g("auth-str") or u.username or ""
if auth:
outbound["auth_str"] = auth
def _parse_bw(v: str) -> int:
"""Parse '100 Mbps' or '100' or 100"""
if not v:
return 0
try:
return int(v.strip().split()[0])
except Exception:
return 0
up = _parse_bw(g("upmbps") or g("up") or g("up_mbps") or "")
dn = _parse_bw(g("downmbps") or g("down") or g("down_mbps") or "")
if up:
outbound["up_mbps"] = up
if dn:
outbound["down_mbps"] = dn
if g("obfs"):
outbound["obfs"] = g("obfs")
tls_block: dict[str, Any] = {"enabled": True}
sni = _first_param(params, "peer", "sni", "servername", "serverName", "server_name", default=host)
if sni:
tls_block["server_name"] = sni
if _truthy(_first_param(params, "allowInsecure", "allow_insecure", "skip-cert-verify", "skip_cert_verify", "insecure")):
tls_block["insecure"] = True
if g("alpn"):
tls_block["alpn"] = [a.strip() for a in g("alpn").split(",") if a.strip()]
_apply_ech_from_value(tls_block, g("ech") or g("echConfig") or g("ech-config") or g("ech_config") or g("echQueryServerName") or g("ech-query-server-name"))
outbound["tls"] = tls_block
return _wrap(outbound)
# ---------- structured dict → outbound ----------
def _clash_stream_settings(p: dict[str, Any]) -> tuple[Optional[dict[str, Any]], Optional[dict[str, Any]]]:
"""Read Clash-style tls/transport options from a proxy dict.
Returns (tls_block, transport_block)."""
tls_block: Optional[dict[str, Any]] = None
transport: Optional[dict[str, Any]] = None
if p.get("tls") is True or p.get("servername") or p.get("sni"):
tls_block = {"enabled": True}
sni = p.get("servername") or p.get("sni")
if sni:
tls_block["server_name"] = sni
if p.get("skip-cert-verify") or p.get("skip_cert_verify"):
tls_block["insecure"] = True
alpn = p.get("alpn")
if alpn:
tls_block["alpn"] = alpn if isinstance(alpn, list) else [alpn]
fp = p.get("client-fingerprint") or p.get("client_fingerprint")
if fp:
tls_block["utls"] = {"enabled": True, "fingerprint": fp}
reality = p.get("reality-opts") or p.get("reality_opts")
if reality and isinstance(reality, dict):
r: dict[str, Any] = {"enabled": True}
if reality.get("public-key") or reality.get("public_key"):
r["public_key"] = reality.get("public-key") or reality.get("public_key")
if reality.get("short-id") is not None or reality.get("short_id") is not None:
r["short_id"] = reality.get("short-id") or reality.get("short_id") or ""
tls_block["reality"] = r
if "utls" not in tls_block:
tls_block["utls"] = {"enabled": True, "fingerprint": "chrome"}
_apply_ech_from_mapping(tls_block, p)
fragment = p.get("tls-fragment") or p.get("tls_fragment") or p.get("fragment")
if _truthy(fragment):
tls_block["fragment"] = True
record_fragment = p.get("tls-record-fragment") or p.get("tls_record_fragment") or p.get("record-fragment") or p.get("record_fragment")
if _truthy(record_fragment):
tls_block["record_fragment"] = True
network = (p.get("network") or "tcp").lower()
if network == "ws":
ws_opts = p.get("ws-opts") or p.get("ws_opts") or {}
t: dict[str, Any] = {"type": "ws"}
if ws_opts.get("path"):
t["path"] = ws_opts["path"]
headers = ws_opts.get("headers") or {}
if headers.get("Host"):
t["headers"] = {"Host": headers["Host"]}
transport = t
elif network == "grpc":
grpc_opts = p.get("grpc-opts") or p.get("grpc_opts") or {}
t = {"type": "grpc"}
sn = grpc_opts.get("grpc-service-name") or grpc_opts.get("grpc_service_name")
if sn:
t["service_name"] = sn
transport = t
elif network in ("http", "h2"):
http_opts = p.get("http-opts") or p.get("http_opts") or {}
t = {"type": "http"}
hosts = http_opts.get("host")
if hosts:
t["host"] = hosts if isinstance(hosts, list) else [hosts]
if http_opts.get("path"):
path = http_opts["path"]
t["path"] = path[0] if isinstance(path, list) else path
transport = t
return tls_block, transport
def _from_clash(p: dict[str, Any]) -> dict[str, Any]:
"""Convert a structured dict into an outbound dict."""
t = (p.get("type") or "").lower()
host = p.get("server", "")
port = int(p.get("port", 0) or 0)
if t == _P["a"]:
outbound: dict[str, Any] = {
"type": _P["a"],
"server": host,
"server_port": port,
"uuid": p.get("uuid", ""),
}
if p.get("flow"):
outbound["flow"] = p["flow"]
tls_block, transport = _clash_stream_settings(p)
if tls_block:
outbound["tls"] = tls_block
if transport:
outbound["transport"] = transport
return outbound
if t == _P["b"]:
outbound = {
"type": _P["b"],
"server": host,
"server_port": port,
"uuid": p.get("uuid", ""),
"security": p.get("cipher") or "auto",
"alter_id": int(p.get("alterId", 0) or 0),
}
tls_block, transport = _clash_stream_settings(p)
if tls_block:
outbound["tls"] = tls_block
if transport:
outbound["transport"] = transport
return outbound
if t == _P["c"]:
outbound = {
"type": _P["c"],
"server": host,
"server_port": port,
"password": p.get("password", ""),
}
tls_block, transport = _clash_stream_settings(p)
if tls_block is None:
tls_block = {"enabled": True}
sni = p.get("sni") or host
if sni:
tls_block["server_name"] = sni
_apply_ech_from_mapping(tls_block, p)
outbound["tls"] = tls_block
if transport:
outbound["transport"] = transport
return outbound
if t == _P["d"]:
outbound = {
"type": _P["d"],
"server": host,
"server_port": port,
"method": p.get("cipher", ""),
"password": p.get("password", ""),
}
plugin = p.get("plugin")
if plugin:
outbound["plugin"] = plugin
plugin_opts = p.get("plugin-opts") or p.get("plugin_opts") or p.get("pluginOpts")
if plugin_opts:
outbound["plugin_opts"] = plugin_opts
network = p.get("network")
if network in ("tcp", "udp"):
outbound["network"] = network
return outbound
if t == _P["f"]:
outbound = {
"type": _P["f"],
"server": host,
"server_port": port,
"password": p.get("password", ""),
}
tls_block = {"enabled": True}
sni = p.get("sni") or p.get("servername") or host
if sni:
tls_block["server_name"] = sni
if p.get("skip-cert-verify"):
tls_block["insecure"] = True
alpn = p.get("alpn")
if alpn:
tls_block["alpn"] = alpn if isinstance(alpn, list) else [alpn]
_apply_ech_from_mapping(tls_block, p)
outbound["tls"] = tls_block
if p.get("obfs"):
ob: dict[str, Any] = {"type": p["obfs"]}
if p.get("obfs-password") or p.get("obfs_password"):
ob["password"] = p.get("obfs-password") or p.get("obfs_password")
outbound["obfs"] = ob
return outbound
if t == _P["h"]:
outbound = {
"type": _P["h"],
"server": host,
"server_port": port,
"password": p.get("password", ""),
}
tls_block = {"enabled": True}
sni = p.get("sni") or p.get("servername") or host
if sni:
tls_block["server_name"] = sni
if p.get("skip-cert-verify"):
tls_block["insecure"] = True
fp = p.get("client-fingerprint") or p.get("client_fingerprint")
if fp:
tls_block["utls"] = {"enabled": True, "fingerprint": fp}
alpn = p.get("alpn")
if alpn:
tls_block["alpn"] = alpn if isinstance(alpn, list) else [alpn]
_apply_ech_from_mapping(tls_block, p)
outbound["tls"] = tls_block
return outbound
if t == _P["i"]:
outbound = {
"type": _P["i"],
"server": host,
"server_port": port,
"uuid": p.get("uuid", ""),
"password": p.get("password", ""),
}
cc = p.get("congestion-controller") or p.get("congestion_controller") or p.get("congestion_control")
if cc:
outbound["congestion_control"] = cc
urm = p.get("udp-relay-mode") or p.get("udp_relay_mode")
if urm:
outbound["udp_relay_mode"] = urm
tls_block = {"enabled": True}
sni = p.get("sni") or p.get("servername") or host
if sni:
tls_block["server_name"] = sni
if p.get("skip-cert-verify"):
tls_block["insecure"] = True
alpn = p.get("alpn")
if alpn:
tls_block["alpn"] = alpn if isinstance(alpn, list) else [alpn]
_apply_ech_from_mapping(tls_block, p)
outbound["tls"] = tls_block
return outbound
if t == _P["j"]:
outbound = {
"type": _P["j"],
"server": host,
"server_port": port,
}
auth = p.get("auth-str") or p.get("auth_str") or p.get("auth")
if auth:
outbound["auth_str"] = auth
def _bw(v: Any) -> int:
if isinstance(v, int):
return v
if isinstance(v, str):
try:
return int(v.strip().split()[0])
except Exception:
return 0
return 0
up = _bw(p.get("up") or p.get("up-mbps") or p.get("up_mbps"))
dn = _bw(p.get("down") or p.get("down-mbps") or p.get("down_mbps"))
if up:
outbound["up_mbps"] = up
if dn:
outbound["down_mbps"] = dn
if p.get("obfs"):
outbound["obfs"] = p["obfs"]
tls_block = {"enabled": True}
sni = p.get("sni") or p.get("servername") or host
if sni:
tls_block["server_name"] = sni
if p.get("skip-cert-verify"):
tls_block["insecure"] = True
alpn = p.get("alpn")
if alpn:
tls_block["alpn"] = alpn if isinstance(alpn, list) else [alpn]
_apply_ech_from_mapping(tls_block, p)
outbound["tls"] = tls_block
return outbound
raise ValueError(f"Unsupported clash type: {t}")
def _parse_k(uri: str) -> dict[str, Any]:
"""Parse pseudo-URI scheme K: clash://base64(json_of_proxy_dict)"""
raw = uri[len(_S["k"]):]
pad = len(raw) % 4
if pad:
raw += "=" * (4 - pad)
proxy = json.loads(base64.b64decode(raw.replace("-", "+").replace("_", "/")).decode("utf-8", errors="replace"))
return _wrap(_from_clash(proxy))
def build_config(uri: str, socks_port: int = SOCKS_INBOUND_PORT) -> dict[str, Any]:
uri = uri.strip()
if uri.startswith(_S["a"]):
cfg = _parse_a(uri)
elif uri.startswith(_S["b"]):
cfg = _parse_b(uri)
elif uri.startswith(_S["c"]):
cfg = _parse_c(uri)
elif uri.startswith(_S["d"]):
cfg = _parse_d(uri)
elif uri.startswith(_S["f"]):
cfg = _parse_f(uri)
elif uri.startswith(_S["g"]):
cfg = _parse_f(_S["f"] + uri[len(_S["g"]):])
elif uri.startswith(_S["h"]):
cfg = _parse_h(uri)
elif uri.startswith(_S["i"]):
cfg = _parse_i(uri)
elif uri.startswith(_S["j"]):
cfg = _parse_j(uri)
elif uri.startswith(_S["k"]):
cfg = _parse_k(uri)
else:
raise ValueError(f"Unsupported scheme: {uri[:16]}...")
if socks_port != SOCKS_INBOUND_PORT:
cfg["inbounds"][0]["listen_port"] = socks_port
return cfg
def needs_worker(uri: str) -> bool:
u = uri.strip()
return any(u.startswith(s) for s in (
_S["a"], _S["b"], _S["c"], _S["d"], _S["e"],
_S["f"], _S["g"], _S["h"], _S["i"], _S["j"], _S["k"]
))
def clash_to_pseudo_uri(proxy: dict[str, Any]) -> str:
"""把 Clash proxy dict 序列化成 clash:// 伪 URI,供统一 worker 使用"""
raw = base64.urlsafe_b64encode(json.dumps(proxy, ensure_ascii=False).encode("utf-8")).decode().rstrip("=")
return _S["k"] + raw
def clash_type_letter(clash_type: str) -> str:
"""Map a proxy type field to a single UI letter."""
t = (clash_type or "").lower()
mapping = {
_P["a"]: "A",
_P["b"]: "B",
_P["c"]: "C",
_P["d"]: "D",
_P["f"]: "F",
_P["h"]: "H",
_P["i"]: "I",
_P["j"]: "J",
}
return mapping.get(t, "?")