libsubconverter/parser/explodes/
vless.rs1use crate::models::proxy_node::combined::CombinedProxy;
2use crate::models::proxy_node::vless::VlessProxy;
3use crate::models::{Proxy, ProxyType};
4use crate::utils::url_decode;
5use std::collections::{HashMap, HashSet};
6use url::Url;
7
8pub fn explode_vless(vless: &str, node: &mut Proxy) -> bool {
10 if !vless.starts_with("vless://") {
12 return false;
13 }
14
15 let url = match Url::parse(vless) {
17 Ok(url) => url,
18 Err(_) => return false,
19 };
20
21 let mut params = HashMap::new();
23 for (key, value) in url.query_pairs() {
24 params.insert(key.to_string(), url_decode(&value));
25 }
26
27 let uuid = match url.username() {
29 "" => return false,
30 username => username.to_string(),
31 };
32
33 let host = match url.host_str() {
35 Some(host) => host,
36 None => return false,
37 };
38 let port = url.port().unwrap_or(443);
39
40 let tls = params
42 .get("security")
43 .map(|s| s.to_lowercase())
44 .map(|s| s.ends_with("tls") || s == "reality")
45 .unwrap_or(false);
46
47 let fingerprint = params
48 .get("fp")
49 .map(|s| s.to_string())
50 .unwrap_or_else(|| "chrome".to_string());
51
52 let alpn = params
53 .get("alpn")
54 .map(|s| {
55 s.split(',')
56 .map(|s| s.trim().to_string())
57 .collect::<HashSet<_>>()
58 })
59 .unwrap_or_default();
60
61 let sni = params.get("sni").map(|s| s.to_string());
62
63 let flow = params.get("flow").map(|s| s.to_string());
64
65 let packet_encoding = params.get("packetEncoding").map(|s| s.to_string());
66 let packet_addr = packet_encoding.as_deref() == Some("packet");
67
68 let network = params
69 .get("type")
70 .map(|s| s.to_lowercase())
71 .unwrap_or_else(|| "tcp".to_string());
72
73 let fake_type = params
74 .get("headerType")
75 .map(|s| s.to_lowercase())
76 .unwrap_or_default();
77
78 let mut vless_proxy = VlessProxy::default();
79 vless_proxy.uuid = uuid;
80 vless_proxy.tls = tls;
81 vless_proxy.alpn = alpn;
82 if let Some(packet_encoding) = packet_encoding {
83 let xudp = packet_encoding != "none";
84 vless_proxy.xudp = Some(xudp);
85 vless_proxy.packet_encoding = Some(packet_encoding);
86 vless_proxy.packet_addr = Some(packet_addr);
87 }
88 vless_proxy.network = Some(network.clone());
89 vless_proxy.servername = sni;
90 vless_proxy.client_fingerprint = Some(fingerprint);
91 vless_proxy.flow = flow;
92
93 if let Some(public_key) = params.get("pbk") {
95 vless_proxy.reality_public_key = Some(public_key.to_string());
96 vless_proxy.reality_short_id = params.get("sid").map(|s| s.to_string());
97 }
98
99 match network.as_str() {
101 "tcp" => {
102 if fake_type != "none" {
103 let mut http_headers = HashMap::new();
104 let mut http_path = vec!["/".to_string()];
105
106 if let Some(host) = params.get("host") {
107 http_headers.insert("Host".to_string(), vec![host.to_string()]);
108 }
109
110 if let Some(path) = params.get("path") {
111 http_path = vec![path.to_string()];
112 }
113
114 vless_proxy.http_method = params.get("method").map(|s| s.to_string());
115 vless_proxy.http_path = Some(http_path[0].clone());
116 vless_proxy.http_headers = Some(http_headers);
117 }
118 }
119 "http" | "h2" => {
120 let mut h2_headers = HashMap::new();
121 let mut h2_path = vec!["/".to_string()];
122
123 if let Some(path) = params.get("path") {
124 h2_path = vec![path.to_string()];
125 }
126
127 if let Some(host) = params.get("host") {
128 h2_headers.insert("Host".to_string(), vec![host.to_string()]);
129 }
130
131 vless_proxy.h2_path = Some(h2_path[0].clone());
132 vless_proxy.h2_host = Some(h2_headers.get("Host").unwrap_or(&vec![]).clone());
133 }
134 "ws" | "httpupgrade" => {
135 let mut ws_headers = HashMap::new();
136 ws_headers.insert("User-Agent".to_string(), "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36".to_string());
137
138 if let Some(host) = params.get("host") {
139 ws_headers.insert("Host".to_string(), host.to_string());
140 }
141
142 vless_proxy.ws_path = params.get("path").map(|s| s.to_string());
143 vless_proxy.ws_headers = Some(ws_headers);
144
145 if let Some(early_data) = params.get("ed") {
146 if let Ok(_med) = early_data.parse::<i32>() {
147 if network == "ws" {
148 } else if network == "httpupgrade" {
150 }
152 }
153 }
154
155 if let Some(_early_data_header) = params.get("eh") {
156 }
158 }
159 "grpc" => {
160 vless_proxy.grpc_service_name = params.get("serviceName").map(|s| s.to_string());
161 }
162 _ => {}
163 }
164
165 node.proxy_type = ProxyType::Vless;
166 node.combined_proxy = Some(CombinedProxy::Vless(vless_proxy));
167 node.remark = url_decode(url.fragment().unwrap_or(""));
168 node.hostname = host.to_string();
169 node.port = port;
170
171 true
172}