libsubconverter/parser/explodes/
quan.rs1use crate::models::{
2 Proxy, HTTP_DEFAULT_GROUP, SSR_DEFAULT_GROUP, SS_DEFAULT_GROUP, TROJAN_DEFAULT_GROUP,
3 V2RAY_DEFAULT_GROUP,
4};
5
6pub fn explode_quan(content: &str, nodes: &mut Vec<Proxy>) -> bool {
9 let lines: Vec<&str> = content.lines().collect();
11
12 let mut success = false;
13
14 for line in lines {
15 let line = line.trim();
17 if line.is_empty() || line.starts_with('#') || line.starts_with(';') {
18 continue;
19 }
20
21 let mut node = Proxy::default();
23 if parse_quan_line(line, &mut node) {
24 nodes.push(node);
25 success = true;
26 }
27 }
28
29 success
30}
31
32fn parse_quan_line(line: &str, node: &mut Proxy) -> bool {
35 let parts: Vec<&str> = line.splitn(2, " = ").collect();
39 if parts.len() != 2 {
40 return false;
41 }
42
43 let name = parts[0].trim();
44 let config = parts[1].trim();
45
46 let config_parts: Vec<&str> = config.split(',').map(|s| s.trim()).collect();
47 if config_parts.is_empty() {
48 return false;
49 }
50
51 match config_parts[0] {
53 "vmess" => parse_quan_vmess(name, config_parts, node),
54 "shadowsocks" => parse_quan_ss(name, config_parts, node),
55 "shadowsocksr" => parse_quan_ssr(name, config_parts, node),
56 "http" => parse_quan_http(name, config_parts, node),
57 "trojan" => parse_quan_trojan(name, config_parts, node),
58 _ => false,
59 }
60}
61
62fn parse_quan_ss(name: &str, config_parts: Vec<&str>, node: &mut Proxy) -> bool {
64 if config_parts.len() < 5 {
66 return false;
67 }
68
69 let server = config_parts[1];
71 let port = match config_parts[2].parse::<u16>() {
72 Ok(p) => p,
73 Err(_) => return false,
74 };
75 if port == 0 {
76 return false; }
78 let method = config_parts[3];
79 let password = config_parts[4];
80
81 let mut plugin = "";
83 let mut plugin_opts = "";
84 let mut udp = None;
85 let mut tfo = None;
86 let mut scv = None;
87
88 for i in 5..config_parts.len() {
90 if config_parts[i].starts_with("obfs=") {
91 plugin = "obfs";
92
93 let obfs_parts: Vec<&str> = config_parts[i][5..].split(',').collect();
94 if !obfs_parts.is_empty() {
95 let mut opts = format!("obfs={}", obfs_parts[0]);
96
97 if obfs_parts.len() > 1 {
98 opts.push_str(&format!(";obfs-host={}", obfs_parts[1]));
99 }
100
101 plugin_opts = Box::leak(opts.into_boxed_str());
102 }
103 } else if config_parts[i] == "udp-relay=true" {
104 udp = Some(true);
105 } else if config_parts[i] == "fast-open=true" {
106 tfo = Some(true);
107 } else if config_parts[i] == "tls-verification=false" {
108 scv = Some(true);
109 }
110 }
111
112 *node = Proxy::ss_construct(
113 SS_DEFAULT_GROUP,
114 name,
115 server,
116 port,
117 password,
118 method,
119 plugin,
120 plugin_opts,
121 udp,
122 tfo,
123 scv,
124 None,
125 "",
126 );
127
128 true
129}
130
131fn parse_quan_ssr(name: &str, config_parts: Vec<&str>, node: &mut Proxy) -> bool {
133 if config_parts.len() < 9 {
135 return false;
136 }
137
138 let server = config_parts[1];
140 let port = match config_parts[2].parse::<u16>() {
141 Ok(p) => p,
142 Err(_) => return false,
143 };
144 if port == 0 {
145 return false; }
147 let method = config_parts[3];
148 let password = config_parts[4];
149 let protocol = config_parts[5];
150 let protocol_param = config_parts[6];
151 let obfs = config_parts[7];
152 let obfs_param = config_parts[8];
153
154 let mut udp = None;
156 let mut tfo = None;
157 let mut scv = None;
158
159 for i in 9..config_parts.len() {
161 if config_parts[i] == "udp-relay=true" {
162 udp = Some(true);
163 } else if config_parts[i] == "fast-open=true" {
164 tfo = Some(true);
165 } else if config_parts[i] == "tls-verification=false" {
166 scv = Some(true);
167 }
168 }
169
170 *node = Proxy::ssr_construct(
171 SSR_DEFAULT_GROUP,
172 name,
173 server,
174 port,
175 protocol,
176 method,
177 obfs,
178 password,
179 obfs_param,
180 protocol_param,
181 udp,
182 tfo,
183 scv,
184 "",
185 );
186
187 true
188}
189
190fn parse_quan_vmess(name: &str, config_parts: Vec<&str>, node: &mut Proxy) -> bool {
193 if config_parts.len() < 6 {
195 return false;
196 }
197
198 let server = config_parts[1];
200 let port = match config_parts[2].parse::<u16>() {
201 Ok(p) => p,
202 Err(_) => return false,
203 };
204 if port == 0 {
205 return false; }
207 let cipher = config_parts[3];
208 let uuid = config_parts[4].replace("\"", ""); let mut group = V2RAY_DEFAULT_GROUP.to_string();
212 let aid = "0".to_string();
213 let mut net = "tcp".to_string();
214 let mut path = String::new();
215 let mut host = String::new();
216 let mut edge = String::new();
217 let mut tls = String::new();
218 let fake_type = "none".to_string();
219
220 for i in 5..config_parts.len() {
222 let option_parts: Vec<&str> = config_parts[i].splitn(2, "=").collect();
223 if option_parts.len() < 2 {
224 continue;
225 }
226
227 let item_name = option_parts[0].trim();
228 let item_val = option_parts[1].trim();
229
230 match item_name {
231 "group" => group = item_val.to_string(),
232 "over-tls" => {
233 tls = if item_val == "true" {
234 "tls".to_string()
235 } else {
236 String::new()
237 }
238 }
239 "tls-host" => host = item_val.to_string(),
240 "obfs-path" => path = item_val.replace("\"", ""), "obfs-header" => {
242 let processed_val = item_val
244 .replace("\"", "")
245 .replace("\r\n", "|")
246 .replace("\n", "|");
247 let headers: Vec<&str> = processed_val.split('|').collect();
248
249 for header in headers {
250 if header.to_lowercase().starts_with("host: ") {
251 host = header[6..].to_string();
252 } else if header.to_lowercase().starts_with("edge: ") {
253 edge = header[6..].to_string();
254 }
255 }
256 }
257 "obfs" => {
258 if item_val == "ws" {
259 net = "ws".to_string();
260 }
261 }
262 _ => {}
263 }
264 }
265
266 if path.is_empty() {
268 path = "/".to_string();
269 }
270
271 *node = Proxy::vmess_construct(
272 &group,
273 name,
274 server,
275 port,
276 &fake_type,
277 &uuid,
278 aid.parse::<u16>().unwrap_or(0),
279 &net,
280 cipher,
281 &path,
282 &host,
283 &edge,
284 &tls,
285 "", None,
287 None,
288 None,
289 None,
290 "",
291 );
292
293 true
294}
295
296fn parse_quan_http(name: &str, config_parts: Vec<&str>, node: &mut Proxy) -> bool {
298 if config_parts.len() < 3 {
300 return false;
301 }
302
303 let server = config_parts[1];
305 let port = match config_parts[2].parse::<u16>() {
306 Ok(p) => p,
307 Err(_) => return false,
308 };
309 if port == 0 {
310 return false; }
312
313 let mut username = "";
315 let mut password = "";
316 let mut is_https = false;
317 let mut tfo = None;
318 let mut scv = None;
319
320 if config_parts.len() > 3 {
322 username = config_parts[3];
323 }
324
325 if config_parts.len() > 4 {
326 password = config_parts[4];
327 }
328
329 for i in 5..config_parts.len() {
331 if config_parts[i] == "over-tls=true" {
332 is_https = true;
333 } else if config_parts[i] == "fast-open=true" {
334 tfo = Some(true);
335 } else if config_parts[i] == "tls-verification=false" {
336 scv = Some(true);
337 }
338 }
339
340 *node = Proxy::http_construct(
341 HTTP_DEFAULT_GROUP,
342 name,
343 server,
344 port,
345 username,
346 password,
347 is_https,
348 tfo,
349 scv,
350 None,
351 "",
352 );
353
354 true
355}
356
357fn parse_quan_trojan(name: &str, config_parts: Vec<&str>, node: &mut Proxy) -> bool {
359 if config_parts.len() < 4 {
361 return false;
362 }
363
364 let server = config_parts[1];
366 let port = match config_parts[2].parse::<u16>() {
367 Ok(p) => p,
368 Err(_) => return false,
369 };
370 if port == 0 {
371 return false; }
373 let password = config_parts[3];
374
375 let mut sni = None;
377 let mut udp = None;
378 let mut tfo = None;
379 let mut scv = None;
380
381 for i in 4..config_parts.len() {
383 if config_parts[i].starts_with("tls-host=") {
384 sni = Some(config_parts[i][9..].to_string());
385 } else if config_parts[i] == "udp-relay=true" {
386 udp = Some(true);
387 } else if config_parts[i] == "fast-open=true" {
388 tfo = Some(true);
389 } else if config_parts[i] == "tls-verification=false" {
390 scv = Some(true);
391 }
392 }
393
394 *node = Proxy::trojan_construct(
395 TROJAN_DEFAULT_GROUP.to_string(),
396 name.to_string(),
397 server.to_string(),
398 port,
399 password.to_string(),
400 None,
401 sni.clone(),
402 None,
403 sni,
404 true,
405 udp,
406 tfo,
407 scv,
408 None,
409 None,
410 );
411
412 true
413}