mirror of
https://github.com/house-of-vanity/v2-uri-parser.git
synced 2025-12-16 06:57:52 +00:00
Merge pull request #16 from Keivan-sf/10-trojan-parser
10 trojan parser
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct VlessUser {
|
pub struct VnextUser {
|
||||||
pub id: Option<String>,
|
pub id: Option<String>,
|
||||||
pub encryption: Option<String>,
|
pub encryption: Option<String>,
|
||||||
pub flow: Option<String>,
|
pub flow: Option<String>,
|
||||||
@@ -10,20 +10,33 @@ pub struct VlessUser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct VlessServerObject {
|
pub struct VnextServerObject {
|
||||||
pub address: Option<String>,
|
pub address: Option<String>,
|
||||||
pub port: Option<u16>,
|
pub port: Option<u16>,
|
||||||
pub users: Option<Vec<VlessUser>>,
|
pub users: Option<Vec<VnextUser>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
pub struct TrojanServerObject {
|
||||||
|
pub address: Option<String>,
|
||||||
|
pub port: Option<u16>,
|
||||||
|
pub password: Option<String>,
|
||||||
|
pub level: Option<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct VlessOutboundSettings {
|
pub struct VlessOutboundSettings {
|
||||||
pub vnext: Vec<VlessServerObject>,
|
pub vnext: Vec<VnextServerObject>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct VmessOutboundSettings {
|
pub struct VmessOutboundSettings {
|
||||||
pub vnext: Vec<VlessServerObject>,
|
pub vnext: Vec<VnextServerObject>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
pub struct TrojanOutboundSettings {
|
||||||
|
pub servers: Vec<TrojanServerObject>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
@@ -31,6 +44,7 @@ pub struct VmessOutboundSettings {
|
|||||||
pub enum OutboundSettings {
|
pub enum OutboundSettings {
|
||||||
Vless(VlessOutboundSettings),
|
Vless(VlessOutboundSettings),
|
||||||
Vmess(VmessOutboundSettings),
|
Vmess(VmessOutboundSettings),
|
||||||
|
Trojan(TrojanOutboundSettings),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ use crate::utils::{inbound_generator, parse_raw_json};
|
|||||||
mod uri_identifier;
|
mod uri_identifier;
|
||||||
mod vless;
|
mod vless;
|
||||||
mod vmess;
|
mod vmess;
|
||||||
|
mod trojan;
|
||||||
|
|
||||||
pub fn get_name(uri: &str) -> String {
|
pub fn get_name(uri: &str) -> String {
|
||||||
let (_, data, _) = get_uri_data(uri);
|
let (_, data, _) = get_uri_data(uri);
|
||||||
@@ -162,6 +163,11 @@ fn get_uri_data(uri: &str) -> (String, RawData, OutboundSettings) {
|
|||||||
let s = vmess::create_outbound_settings(&d);
|
let s = vmess::create_outbound_settings(&d);
|
||||||
(String::from("vmess"), d, s)
|
(String::from("vmess"), d, s)
|
||||||
}
|
}
|
||||||
|
Some(uri_identifier::Protocols::Trojan) => {
|
||||||
|
let d = trojan::data::get_data(uri);
|
||||||
|
let s = trojan::create_outbound_settings(&d);
|
||||||
|
(String::from("trojan"), d, s)
|
||||||
|
}
|
||||||
Some(_) => {
|
Some(_) => {
|
||||||
panic!("The protocol was recognized but is not supported yet");
|
panic!("The protocol was recognized but is not supported yet");
|
||||||
}
|
}
|
||||||
|
|||||||
62
src/parser/trojan/data.rs
Normal file
62
src/parser/trojan/data.rs
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
use crate::config_models::RawData;
|
||||||
|
use crate::parser::trojan::models;
|
||||||
|
use crate::utils::{get_parameter_value, url_decode};
|
||||||
|
use http::Uri;
|
||||||
|
|
||||||
|
pub fn get_data(uri: &str) -> RawData {
|
||||||
|
let data = uri.split_once("trojan://").unwrap().1;
|
||||||
|
let query_and_name = uri.split_once("?").unwrap().1;
|
||||||
|
let (raw_query, name) = query_and_name
|
||||||
|
.split_once("#")
|
||||||
|
.unwrap_or((query_and_name, ""));
|
||||||
|
let parsed_address = parse_trojan_address(data.split_once("?").unwrap().0);
|
||||||
|
let query: Vec<(&str, &str)> = querystring::querify(raw_query);
|
||||||
|
|
||||||
|
return RawData {
|
||||||
|
remarks: url_decode(Some(String::from(name))).unwrap_or(String::from("")),
|
||||||
|
uuid: Some(parsed_address.uuid),
|
||||||
|
port: Some(parsed_address.port),
|
||||||
|
address: Some(parsed_address.address),
|
||||||
|
alpn: url_decode(get_parameter_value(&query, "alpn")),
|
||||||
|
path: url_decode(get_parameter_value(&query, "path")),
|
||||||
|
authority: url_decode(get_parameter_value(&query, "authority")),
|
||||||
|
pbk: url_decode(get_parameter_value(&query, "pbk")),
|
||||||
|
security: get_parameter_value(&query, "security"),
|
||||||
|
sid: url_decode(get_parameter_value(&query, "sid")),
|
||||||
|
flow: get_parameter_value(&query, "flow"),
|
||||||
|
sni: get_parameter_value(&query, "sni"),
|
||||||
|
fp: url_decode(get_parameter_value(&query, "fp")),
|
||||||
|
r#type: get_parameter_value(&query, "type"),
|
||||||
|
encryption: get_parameter_value(&query, "encryption"),
|
||||||
|
header_type: get_parameter_value(&query, "headerType"),
|
||||||
|
host: url_decode(get_parameter_value(&query, "host")),
|
||||||
|
seed: url_decode(get_parameter_value(&query, "seed")),
|
||||||
|
quic_security: get_parameter_value(&query, "quicSecurity"),
|
||||||
|
key: get_parameter_value(&query, "key"),
|
||||||
|
mode: url_decode(get_parameter_value(&query, "mode")),
|
||||||
|
service_name: url_decode(get_parameter_value(&query, "serviceName")),
|
||||||
|
vnext_security: None,
|
||||||
|
slpn: get_parameter_value(&query, "slpn"),
|
||||||
|
spx: url_decode(get_parameter_value(&query, "spx")),
|
||||||
|
extra: url_decode(get_parameter_value(&query, "extra")),
|
||||||
|
allowInsecure: get_parameter_value(&query, "allowInsecure"),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_trojan_address(raw_data: &str) -> models::TrojanAddress {
|
||||||
|
let (uuid, raw_address): (String, &str) = match raw_data.split_once("@") {
|
||||||
|
None => {
|
||||||
|
panic!("Wrong trojan format, no `@` found in the address");
|
||||||
|
}
|
||||||
|
Some(data) => (String::from(data.0), data.1),
|
||||||
|
};
|
||||||
|
let address_wo_slash = raw_address.strip_suffix("/").unwrap_or(raw_address);
|
||||||
|
|
||||||
|
let parsed = address_wo_slash.parse::<Uri>().unwrap();
|
||||||
|
|
||||||
|
return models::TrojanAddress {
|
||||||
|
uuid: url_decode(Some(uuid)).unwrap(),
|
||||||
|
address: parsed.host().unwrap().to_string(),
|
||||||
|
port: parsed.port().unwrap().as_u16(),
|
||||||
|
};
|
||||||
|
}
|
||||||
14
src/parser/trojan/mod.rs
Normal file
14
src/parser/trojan/mod.rs
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
pub mod data;
|
||||||
|
mod models;
|
||||||
|
use crate::config_models::*;
|
||||||
|
|
||||||
|
pub fn create_outbound_settings(data: &RawData) -> OutboundSettings {
|
||||||
|
return OutboundSettings::Trojan(TrojanOutboundSettings {
|
||||||
|
servers: vec![TrojanServerObject {
|
||||||
|
address: data.address.clone(),
|
||||||
|
port: data.port,
|
||||||
|
password: data.uuid.clone(),
|
||||||
|
level: Some(0),
|
||||||
|
}],
|
||||||
|
});
|
||||||
|
}
|
||||||
5
src/parser/trojan/models.rs
Normal file
5
src/parser/trojan/models.rs
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
pub struct TrojanAddress {
|
||||||
|
pub uuid: String,
|
||||||
|
pub address: String,
|
||||||
|
pub port: u16,
|
||||||
|
}
|
||||||
@@ -13,7 +13,7 @@ pub fn get_data(uri: &str) -> RawData {
|
|||||||
let query: Vec<(&str, &str)> = querystring::querify(raw_query);
|
let query: Vec<(&str, &str)> = querystring::querify(raw_query);
|
||||||
|
|
||||||
return RawData {
|
return RawData {
|
||||||
remarks: String::from(name),
|
remarks: url_decode(Some(String::from(name))).unwrap_or(String::from("")),
|
||||||
uuid: Some(parsed_address.uuid),
|
uuid: Some(parsed_address.uuid),
|
||||||
port: Some(parsed_address.port),
|
port: Some(parsed_address.port),
|
||||||
address: Some(parsed_address.address),
|
address: Some(parsed_address.address),
|
||||||
|
|||||||
@@ -4,10 +4,10 @@ use crate::{config_models::*, utils::parse_raw_json};
|
|||||||
|
|
||||||
pub fn create_outbound_settings(data: &RawData) -> OutboundSettings {
|
pub fn create_outbound_settings(data: &RawData) -> OutboundSettings {
|
||||||
return OutboundSettings::Vless(VlessOutboundSettings {
|
return OutboundSettings::Vless(VlessOutboundSettings {
|
||||||
vnext: vec![VlessServerObject {
|
vnext: vec![VnextServerObject {
|
||||||
port: data.port,
|
port: data.port,
|
||||||
address: data.address.clone(),
|
address: data.address.clone(),
|
||||||
users: Some(vec![VlessUser {
|
users: Some(vec![VnextUser {
|
||||||
id: data.uuid.clone(),
|
id: data.uuid.clone(),
|
||||||
flow: data.flow.clone(),
|
flow: data.flow.clone(),
|
||||||
encryption: Some(data.encryption.clone().unwrap_or(String::from("none"))),
|
encryption: Some(data.encryption.clone().unwrap_or(String::from("none"))),
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ fn get_raw_data_from_base64(decoded_base64: &Vec<u8>) -> RawData {
|
|||||||
let json = serde_json::from_str::<Value>(json_str).unwrap();
|
let json = serde_json::from_str::<Value>(json_str).unwrap();
|
||||||
|
|
||||||
return RawData {
|
return RawData {
|
||||||
remarks: get_str_field(&json, "ps").unwrap_or(String::from("")),
|
remarks: url_decode(get_str_field(&json, "ps")).unwrap_or(String::from("")),
|
||||||
uuid: get_str_field(&json, "id"),
|
uuid: get_str_field(&json, "id"),
|
||||||
port: get_str_field(&json, "port")
|
port: get_str_field(&json, "port")
|
||||||
.and_then(|s| Some(s.parse::<u16>().expect("port is not a number"))),
|
.and_then(|s| Some(s.parse::<u16>().expect("port is not a number"))),
|
||||||
|
|||||||
@@ -4,10 +4,10 @@ use crate::{config_models::*, utils::parse_raw_json};
|
|||||||
|
|
||||||
pub fn create_outbound_settings(data: &RawData) -> OutboundSettings {
|
pub fn create_outbound_settings(data: &RawData) -> OutboundSettings {
|
||||||
return OutboundSettings::Vmess(VmessOutboundSettings {
|
return OutboundSettings::Vmess(VmessOutboundSettings {
|
||||||
vnext: vec![VlessServerObject {
|
vnext: vec![VnextServerObject {
|
||||||
port: data.port,
|
port: data.port,
|
||||||
address: data.address.clone(),
|
address: data.address.clone(),
|
||||||
users: Some(vec![VlessUser {
|
users: Some(vec![VnextUser {
|
||||||
id: data.uuid.clone(),
|
id: data.uuid.clone(),
|
||||||
flow: data.flow.clone(),
|
flow: data.flow.clone(),
|
||||||
encryption: Some(data.encryption.clone().unwrap_or(String::from("none"))),
|
encryption: Some(data.encryption.clone().unwrap_or(String::from("none"))),
|
||||||
|
|||||||
Reference in New Issue
Block a user