libsubconverter/parser/explodes/
trojan.rs1use crate::{models::TROJAN_DEFAULT_GROUP, utils::url_decode, Proxy};
2use std::collections::HashMap;
3use url::Url;
4
5pub fn explode_trojan(trojan: &str, node: &mut Proxy) -> bool {
7 if !trojan.starts_with("trojan://") {
9 return false;
10 }
11
12 let url = match Url::parse(trojan) {
14 Ok(url) => url,
15 Err(_) => return false,
16 };
17
18 let password = url.username();
20 if password.is_empty() {
21 return false;
22 }
23
24 let host = match url.host_str() {
26 Some(host) => host,
27 None => return false,
28 };
29 let port = url.port().unwrap_or(443);
30
31 if port == 0 {
33 return false;
34 }
35
36 let mut params = HashMap::new();
38 for (key, value) in url.query_pairs() {
39 params.insert(key.to_string(), url_decode(&value));
40 }
41
42 let sni = params
44 .get("sni")
45 .map(|s| s.to_string())
46 .or_else(|| params.get("peer").map(|s| s.to_string()));
47
48 let skip_cert_verify = params
50 .get("allowInsecure")
51 .map(|s| s == "1" || s.to_lowercase() == "true");
52
53 let tfo = params
55 .get("tfo")
56 .map(|s| s == "1" || s.to_lowercase() == "true");
57
58 let group = params
60 .get("group")
61 .map(|s| url_decode(s))
62 .unwrap_or_else(|| TROJAN_DEFAULT_GROUP.to_string());
63
64 let mut network = None;
66 let mut path = None;
67
68 if params.get("ws").map(|s| s == "1").unwrap_or(false) {
69 network = Some("ws".to_string());
70 path = params.get("wspath").map(|s| s.to_string());
71 } else if params.get("type").map(|s| s == "ws").unwrap_or(false) {
72 network = Some("ws".to_string());
73 if let Some(p) = params.get("path") {
74 let p_str = p.to_string();
75 if p_str.starts_with("%2F") {
76 path = Some(url_decode(&p_str));
77 } else {
78 path = Some(p_str);
79 }
80 }
81 }
82
83 let remark = url_decode(&url.fragment().unwrap_or(""));
85 let formatted_remark = if remark.is_empty() {
86 format!("{} ({})", host, port)
87 } else {
88 remark.to_string()
89 };
90
91 *node = Proxy::trojan_construct(
93 group,
94 formatted_remark,
95 host.to_string(),
96 port,
97 password.to_string(),
98 network,
99 sni.clone(),
100 path,
101 sni,
102 true, None, tfo, skip_cert_verify, None, None, );
109
110 true
111}
112
113pub fn explode_trojan_go(trojan_go: &str, node: &mut Proxy) -> bool {
115 if !trojan_go.starts_with("trojan-go://") {
117 return false;
118 }
119
120 let url = match Url::parse(trojan_go) {
122 Ok(url) => url,
123 Err(_) => return false,
124 };
125
126 let password = url.username();
128 if password.is_empty() {
129 return false;
130 }
131
132 let host = match url.host_str() {
134 Some(host) => host,
135 None => return false,
136 };
137 let port = url.port().unwrap_or(443);
138
139 if port == 0 {
141 return false;
142 }
143
144 let mut params = HashMap::new();
146 for (key, value) in url.query_pairs() {
147 params.insert(key.to_string(), url_decode(&value));
148 }
149
150 let network = params.get("type").map(|s| s.to_string());
152 let host_param = params.get("host").map(|s| s.to_string());
153 let path = params.get("path").map(|s| s.to_string());
154 let sni = params.get("sni").map(|s| s.to_string());
155 let skip_cert_verify = params
157 .get("allowInsecure")
158 .map(|s| s == "1" || s.to_lowercase() == "true");
159
160 let tfo = params
162 .get("tfo")
163 .map(|s| s == "1" || s.to_lowercase() == "true");
164
165 let group = params
167 .get("group")
168 .map_or_else(|| TROJAN_DEFAULT_GROUP, |s| s);
169
170 let remark = url_decode(url.fragment().unwrap_or(""));
172 let formatted_remark = if remark.is_empty() {
173 format!("{} ({})", host, port)
174 } else {
175 remark.to_string()
176 };
177
178 *node = Proxy::trojan_construct(
180 group.to_string(),
181 formatted_remark,
182 host.to_string(),
183 port,
184 password.to_string(),
185 network,
186 host_param,
187 path,
188 sni,
189 true, None, tfo, skip_cert_verify, None, None, );
196
197 true
198}