libsubconverter/parser/explodes/
netch.rs1use crate::models::{
2 Proxy, HTTP_DEFAULT_GROUP, SOCKS_DEFAULT_GROUP, SSR_DEFAULT_GROUP, SS_DEFAULT_GROUP,
3 TROJAN_DEFAULT_GROUP, V2RAY_DEFAULT_GROUP,
4};
5use crate::utils::base64::{base64_encode, url_safe_base64_decode};
6use serde_json::Value;
7
8pub fn explode_netch(netch: &str, node: &mut Proxy) -> bool {
11 if !netch.starts_with("Netch://") {
13 return false;
14 }
15
16 let decoded = url_safe_base64_decode(&netch[8..]);
17
18 let json: Value = match serde_json::from_str(&decoded) {
20 Ok(j) => j,
21 Err(_) => return false,
22 };
23
24 if !json.is_object() {
26 return false;
27 }
28
29 let type_str = json.get("Type").and_then(Value::as_str).unwrap_or("");
31 if type_str.is_empty() {
32 return false;
33 }
34
35 let remark = json.get("Remark").and_then(Value::as_str).unwrap_or("");
36 let server = json.get("Hostname").and_then(Value::as_str).unwrap_or("");
37 let port_str = json.get("Port").and_then(Value::as_str).unwrap_or("0");
38
39 if port_str == "0" {
40 return false;
41 }
42
43 let port = port_str.parse::<u16>().unwrap_or(0);
44 if port == 0 {
45 return false;
46 }
47
48 let group = json.get("Group").and_then(Value::as_str).unwrap_or("");
50 let udp = json.get("EnableUDP").and_then(Value::as_bool);
51 let tfo = json.get("EnableTFO").and_then(Value::as_bool);
52 let scv = json.get("AllowInsecure").and_then(Value::as_bool);
53
54 let remark = if remark.is_empty() {
56 format!("{}:{}", server, port)
57 } else {
58 remark.to_string()
59 };
60
61 match type_str {
63 "Shadowsocks" | "SS" => {
64 let method = json
65 .get("EncryptMethod")
66 .and_then(Value::as_str)
67 .or_else(|| json.get("Method").and_then(Value::as_str))
68 .unwrap_or("");
69 let password = json.get("Password").and_then(Value::as_str).unwrap_or("");
70
71 if method.is_empty() || password.is_empty() {
72 return false;
73 }
74
75 let plugin = json.get("Plugin").and_then(Value::as_str).unwrap_or("");
76 let plugin_opts = json
77 .get("PluginOption")
78 .and_then(Value::as_str)
79 .unwrap_or("");
80
81 let group = if group.is_empty() {
82 SS_DEFAULT_GROUP
83 } else {
84 group
85 };
86
87 *node = Proxy::ss_construct(
88 group,
89 &remark,
90 server,
91 port,
92 password,
93 method,
94 plugin,
95 plugin_opts,
96 udp,
97 tfo,
98 scv,
99 None,
100 "",
101 );
102
103 true
104 }
105 "ShadowsocksR" | "SSR" => {
106 let method = json
107 .get("EncryptMethod")
108 .and_then(Value::as_str)
109 .or_else(|| json.get("Method").and_then(Value::as_str))
110 .unwrap_or("");
111 let password = json.get("Password").and_then(Value::as_str).unwrap_or("");
112 let protocol = json.get("Protocol").and_then(Value::as_str).unwrap_or("");
113 let obfs = json.get("OBFS").and_then(Value::as_str).unwrap_or("");
114 let protocol_param = json
115 .get("ProtocolParam")
116 .and_then(Value::as_str)
117 .unwrap_or("");
118 let obfs_param = json.get("OBFSParam").and_then(Value::as_str).unwrap_or("");
119
120 if method.is_empty() || password.is_empty() || protocol.is_empty() || obfs.is_empty() {
121 return false;
122 }
123
124 let group = if group.is_empty() {
125 SSR_DEFAULT_GROUP
126 } else {
127 group
128 };
129
130 *node = Proxy::ssr_construct(
131 group,
132 &remark,
133 server,
134 port,
135 protocol,
136 method,
137 obfs,
138 password,
139 obfs_param,
140 protocol_param,
141 udp,
142 tfo,
143 scv,
144 "",
145 );
146
147 true
148 }
149 "SOCKS5" | "Socks5" => {
150 let username = json.get("Username").and_then(Value::as_str).unwrap_or("");
151 let password = json.get("Password").and_then(Value::as_str).unwrap_or("");
152
153 let group = if group.is_empty() {
154 SOCKS_DEFAULT_GROUP
155 } else {
156 group
157 };
158
159 *node = Proxy::socks_construct(
160 group, &remark, server, port, username, password, udp, tfo, scv, "",
161 );
162
163 true
164 }
165 "HTTP" | "HTTPS" => {
166 let username = json.get("Username").and_then(Value::as_str).unwrap_or("");
167 let password = json.get("Password").and_then(Value::as_str).unwrap_or("");
168 let is_https = type_str == "HTTPS";
169
170 let group = if group.is_empty() {
171 HTTP_DEFAULT_GROUP
172 } else {
173 group
174 };
175
176 *node = Proxy::http_construct(
177 group, &remark, server, port, username, password, is_https, tfo, scv, None, "",
178 );
179
180 true
181 }
182 "Trojan" => {
183 let password = json.get("Password").and_then(Value::as_str).unwrap_or("");
184 if password.is_empty() {
185 return false;
186 }
187
188 let sni = json
189 .get("Host")
190 .and_then(Value::as_str)
191 .or_else(|| json.get("ServerName").and_then(Value::as_str))
192 .map(|s| s.to_string());
193
194 let group = if group.is_empty() {
195 TROJAN_DEFAULT_GROUP
196 } else {
197 group
198 };
199
200 *node = Proxy::trojan_construct(
201 group.to_string(),
202 remark,
203 server.to_string(),
204 port,
205 password.to_string(),
206 None,
207 sni.clone(),
208 None,
209 sni,
210 true,
211 udp,
212 tfo,
213 scv,
214 None,
215 None,
216 );
217
218 true
219 }
220 "VMess" => {
221 let uuid = json
222 .get("UserID")
223 .and_then(Value::as_str)
224 .or_else(|| json.get("Id").and_then(Value::as_str))
225 .unwrap_or("");
226 if uuid.is_empty() {
227 return false;
228 }
229
230 let alter_id = json
231 .get("AlterID")
232 .and_then(Value::as_u64)
233 .or_else(|| json.get("AlterId").and_then(Value::as_u64))
234 .unwrap_or(0) as u16;
235 let network = json
236 .get("TransferProtocol")
237 .and_then(Value::as_str)
238 .or_else(|| json.get("Network").and_then(Value::as_str))
239 .unwrap_or("tcp");
240 let security = json
241 .get("EncryptMethod")
242 .and_then(Value::as_str)
243 .or_else(|| json.get("Security").and_then(Value::as_str))
244 .unwrap_or("auto");
245 let tls = json
246 .get("TLSSecure")
247 .and_then(Value::as_bool)
248 .or_else(|| json.get("TLS").and_then(Value::as_bool))
249 .unwrap_or(false);
250
251 let host = json.get("Host").and_then(Value::as_str).unwrap_or("");
252 let path = json.get("Path").and_then(Value::as_str).unwrap_or("/");
253 let sni = json.get("ServerName").and_then(Value::as_str).unwrap_or("");
254 let fake_type = json.get("FakeType").and_then(Value::as_str).unwrap_or("");
255 let edge = json.get("Edge").and_then(Value::as_str).unwrap_or("");
256
257 let group = if group.is_empty() {
258 V2RAY_DEFAULT_GROUP
259 } else {
260 group
261 };
262
263 *node = Proxy::vmess_construct(
264 group,
265 &remark,
266 server,
267 port,
268 fake_type,
269 uuid,
270 alter_id,
271 network,
272 security,
273 path,
274 host,
275 edge,
276 if tls { "tls" } else { "" },
277 sni,
278 udp,
279 tfo,
280 scv,
281 None,
282 "",
283 );
284
285 true
286 }
287 _ => false,
288 }
289}
290
291pub fn explode_netch_conf(content: &str, nodes: &mut Vec<Proxy>) -> bool {
294 let json: Value = match serde_json::from_str(content) {
296 Ok(j) => j,
297 Err(_) => return false,
298 };
299
300 if !json.is_object() || !json.get("Server").is_some() {
302 return false;
303 }
304
305 let servers = match json.get("Server") {
306 Some(Value::Array(arr)) => arr,
307 _ => return false,
308 };
309
310 let mut success = false;
311
312 for server in servers {
314 let server_str = match serde_json::to_string(server) {
315 Ok(s) => s,
316 Err(_) => continue,
317 };
318
319 let netch_url = format!("Netch://{}", base64_encode(&server_str));
321
322 let mut node = Proxy::default();
323 if explode_netch(&netch_url, &mut node) {
324 nodes.push(node);
325 success = true;
326 }
327 }
328
329 success
330}