use crate::{utils::url_decode, Proxy};
use regex::Regex;
use std::collections::HashMap;
use url::Url;
pub fn explode_wireguard(wireguard: &str, node: &mut Proxy) -> bool {
if !wireguard.starts_with("wireguard://") {
return false;
}
let url = match Url::parse(wireguard) {
Ok(url) => url,
Err(_) => return false,
};
let mut params = HashMap::new();
for (key, value) in url.query_pairs() {
params.insert(key.to_string(), url_decode(&value));
}
let private_key = match params.get("privateKey") {
Some(key) => key,
None => return false,
};
let public_key = match params.get("publicKey") {
Some(key) => key,
None => return false,
};
let host = match url.host_str() {
Some(host) => host,
None => return false,
};
let port = url.port().unwrap_or(51820);
let preshared_key = params.get("presharedKey").map(|s| s.as_str()).unwrap_or("");
let self_ip = params
.get("selfIP")
.map(|s| s.as_str())
.unwrap_or("10.0.0.2");
let self_ipv6 = params.get("selfIPv6").map(|s| s.as_str()).unwrap_or("");
let mtu = params
.get("mtu")
.map(|s| s.parse::<u16>().unwrap_or(1420))
.unwrap_or(1420);
let keep_alive = params
.get("keepAlive")
.map(|s| s.parse::<u16>().unwrap_or(25))
.unwrap_or(25);
let dns_str = params.get("dns").map(|s| s.as_str()).unwrap_or("");
let dns_servers: Vec<String> = if dns_str.is_empty() {
vec!["1.1.1.1".to_string()]
} else {
dns_str.split(',').map(|s| s.trim().to_string()).collect()
};
let remark = url_decode(url.fragment().unwrap_or(""));
let formatted_remark = if remark.is_empty() {
format!("{} ({})", host, port)
} else {
remark.to_string()
};
*node = Proxy::wireguard_construct(
"WireGuard".to_string(),
formatted_remark,
host.to_string(),
port,
self_ip.to_string(),
self_ipv6.to_string(),
private_key.to_string(),
public_key.to_string(),
preshared_key.to_string(),
dns_servers,
Some(mtu),
Some(keep_alive),
"https://www.gstatic.com/generate_204".to_string(),
"".to_string(),
None,
None,
);
parse_peers(wireguard, node);
true
}
pub fn parse_peers(data: &str, node: &mut Proxy) -> bool {
let peer_regex = Regex::new(r"\((.*?)\)").unwrap();
let peers: Vec<&str> = peer_regex
.captures_iter(data)
.filter_map(|cap| cap.get(1))
.map(|m| m.as_str())
.collect();
if peers.is_empty() {
return false;
}
let peer = peers[0];
let pair_regex = Regex::new(r#"([a-z-]+) ?= ?([^" ),]+|".*?"),? ?"#).unwrap();
let pairs: Vec<(String, String)> = pair_regex
.captures_iter(peer)
.filter_map(|cap| {
if let (Some(key), Some(val)) = (cap.get(1), cap.get(2)) {
Some((key.as_str().to_string(), val.as_str().to_string()))
} else {
None
}
})
.collect();
if pairs.is_empty() {
return false;
}
for (key, val) in pairs {
match key.as_str() {
"public-key" => {
node.public_key = Some(val);
}
"endpoint" => {
if let Some(idx) = val.rfind(':') {
node.hostname = val[..idx].to_string();
if let Ok(port) = val[idx + 1..].parse::<u16>() {
node.port = port;
}
}
}
"client-id" => {
node.client_id = Some(val);
}
"allowed-ips" => {
node.allowed_ips = val.trim_matches('"').to_string();
}
_ => {}
}
}
true
}