use crate::models::{Proxy, SOCKS_DEFAULT_GROUP};
use crate::utils::base64::url_safe_base64_decode;
use std::collections::HashMap;
use url::Url;
pub fn explode_socks(link: &str, node: &mut Proxy) -> bool {
if link.starts_with("socks://") {
return parse_v2rayn_socks(link, node);
}
else if link.starts_with("https://t.me/socks") || link.starts_with("tg://socks") {
return parse_telegram_socks(link, node);
}
false
}
fn parse_v2rayn_socks(link: &str, node: &mut Proxy) -> bool {
let mut remarks = String::new();
let mut trimmed_link = link.to_string();
if let Some(pos) = link.find('#') {
remarks = link[pos + 1..].to_string();
trimmed_link = link[..pos].to_string();
}
let decoded = url_safe_base64_decode(&trimmed_link[8..]);
if decoded.is_empty() {
return false;
}
let mut username = String::new();
let mut password = String::new();
let mut _server = String::new();
let mut _port = 0;
if decoded.contains('@') {
let parts: Vec<&str> = decoded.split('@').collect();
if parts.len() < 2 {
return false;
}
let userinfo: Vec<&str> = parts[0].split(':').collect();
if userinfo.len() < 2 {
return false;
}
username = userinfo[0].to_string();
password = userinfo[1].to_string();
let server_port: Vec<&str> = parts[1].split(':').collect();
if server_port.len() < 2 {
return false;
}
_server = server_port[0].to_string();
_port = match server_port[1].parse::<u16>() {
Ok(p) => p,
Err(_) => return false,
};
} else {
let server_port: Vec<&str> = decoded.split(':').collect();
if server_port.len() < 2 {
return false;
}
_server = server_port[0].to_string();
_port = match server_port[1].parse::<u16>() {
Ok(p) => p,
Err(_) => return false,
};
}
if _port == 0 {
return false;
}
if remarks.is_empty() {
remarks = format!("{} ({})", _server, _port);
}
*node = Proxy::socks_construct(
SOCKS_DEFAULT_GROUP,
&remarks,
&_server,
_port,
&username,
&password,
None,
None,
None,
"",
);
true
}
fn parse_telegram_socks(link: &str, node: &mut Proxy) -> bool {
let url = match Url::parse(link) {
Ok(url) => url,
Err(_) => return false,
};
let query_pairs: HashMap<String, String> = url
.query_pairs()
.map(|(k, v)| (k.to_string(), v.to_string()))
.collect();
let server = match query_pairs.get("server") {
Some(s) => s,
None => return false,
};
let port_str = match query_pairs.get("port") {
Some(p) => p,
None => return false,
};
let port = match port_str.parse::<u16>() {
Ok(p) => p,
Err(_) => return false,
};
if port == 0 {
return false;
}
let username = query_pairs.get("user").map_or("", |s| s);
let password = query_pairs.get("pass").map_or("", |s| s);
let group = query_pairs.get("group").map_or(SOCKS_DEFAULT_GROUP, |s| s);
let remarks = if let Some(r) = query_pairs.get("remarks") {
if !r.is_empty() {
r.as_str()
} else {
&format!("{} ({})", server, port)
}
} else {
&format!("{} ({})", server, port)
};
*node = Proxy::socks_construct(
group, remarks, server, port, username, password, None, None, None, "",
);
true
}