mirror of
https://github.com/house-of-vanity/v2-uri-parser.git
synced 2025-12-16 06:57:52 +00:00
Parse base64 vmess uri
This commit is contained in:
7
Cargo.lock
generated
7
Cargo.lock
generated
@@ -59,6 +59,12 @@ dependencies = [
|
|||||||
"windows-sys",
|
"windows-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "base64"
|
||||||
|
version = "0.22.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bytes"
|
name = "bytes"
|
||||||
version = "1.10.1"
|
version = "1.10.1"
|
||||||
@@ -275,6 +281,7 @@ checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
|
|||||||
name = "v2parser"
|
name = "v2parser"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"base64",
|
||||||
"clap",
|
"clap",
|
||||||
"http",
|
"http",
|
||||||
"querystring",
|
"querystring",
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ edition = "2021"
|
|||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
base64 = "0.22.1"
|
||||||
clap = { version = "4.4.6", features = ["derive"] }
|
clap = { version = "4.4.6", features = ["derive"] }
|
||||||
http = "1.3.1"
|
http = "1.3.1"
|
||||||
querystring = "1.1.0"
|
querystring = "1.1.0"
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ pub struct VlessUser {
|
|||||||
pub encryption: Option<String>,
|
pub encryption: Option<String>,
|
||||||
pub flow: Option<String>,
|
pub flow: Option<String>,
|
||||||
pub level: Option<u8>,
|
pub level: Option<u8>,
|
||||||
|
pub security: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
@@ -186,6 +187,7 @@ pub struct Config {
|
|||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
pub struct RawData {
|
pub struct RawData {
|
||||||
pub security: Option<String>,
|
pub security: Option<String>,
|
||||||
|
pub vnext_security: Option<String>,
|
||||||
pub sni: Option<String>,
|
pub sni: Option<String>,
|
||||||
pub fp: Option<String>,
|
pub fp: Option<String>,
|
||||||
pub pbk: Option<String>,
|
pub pbk: Option<String>,
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ pub fn get_data(uri: &str) -> RawData {
|
|||||||
key: get_parameter_value(&query, "key"),
|
key: get_parameter_value(&query, "key"),
|
||||||
mode: url_decode(get_parameter_value(&query, "mode")),
|
mode: url_decode(get_parameter_value(&query, "mode")),
|
||||||
service_name: url_decode(get_parameter_value(&query, "serviceName")),
|
service_name: url_decode(get_parameter_value(&query, "serviceName")),
|
||||||
|
vnext_security: None,
|
||||||
slpn: get_parameter_value(&query, "slpn"),
|
slpn: get_parameter_value(&query, "slpn"),
|
||||||
spx: url_decode(get_parameter_value(&query, "spx")),
|
spx: url_decode(get_parameter_value(&query, "spx")),
|
||||||
extra: url_decode(get_parameter_value(&query, "extra")),
|
extra: url_decode(get_parameter_value(&query, "extra")),
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ pub fn create_outbound_settings(data: &RawData) -> OutboundSettings {
|
|||||||
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"))),
|
||||||
level: Some(0),
|
level: Some(0),
|
||||||
|
security: None,
|
||||||
}]),
|
}]),
|
||||||
}],
|
}],
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,11 +1,70 @@
|
|||||||
use crate::config_models::RawData;
|
use crate::config_models::RawData;
|
||||||
use crate::parser::vmess::models::{self, VmessAddress};
|
use crate::parser::vmess::models::{self, VmessAddress};
|
||||||
use crate::utils::{get_parameter_value, url_decode};
|
use crate::utils::{get_parameter_value, url_decode};
|
||||||
|
use base64::{engine::general_purpose, Engine};
|
||||||
use http::Uri;
|
use http::Uri;
|
||||||
|
use serde_json::Value;
|
||||||
|
|
||||||
pub fn get_data(uri: &str) -> RawData {
|
pub fn get_data(uri: &str) -> RawData {
|
||||||
let data = uri.split_once("vmess://").unwrap().1;
|
let data = uri.split_once("vmess://").unwrap().1;
|
||||||
|
|
||||||
|
return match general_purpose::STANDARD.decode(data) {
|
||||||
|
Ok(decoded) => get_raw_data_from_base64(&decoded),
|
||||||
|
Err(_) => get_raw_data_from_uri(data),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_raw_data_from_base64(decoded_base64: &Vec<u8>) -> RawData {
|
||||||
|
let json_str = std::str::from_utf8(decoded_base64).unwrap();
|
||||||
|
let json = serde_json::from_str::<Value>(json_str).unwrap();
|
||||||
|
|
||||||
|
return RawData {
|
||||||
|
uuid: get_str_field(&json, "id"),
|
||||||
|
port: get_str_field(&json, "port")
|
||||||
|
.and_then(|s| Some(s.parse::<u16>().expect("port is not a number"))),
|
||||||
|
address: get_str_field(&json, "add"),
|
||||||
|
alpn: url_decode(get_str_field(&json, "alpn")),
|
||||||
|
path: url_decode(get_str_field(&json, "path")),
|
||||||
|
authority: url_decode(get_str_field(&json, "host")),
|
||||||
|
// this probably does not exist in vmess uri
|
||||||
|
pbk: url_decode(get_str_field(&json, "pbk")),
|
||||||
|
security: get_str_field(&json, "tls"),
|
||||||
|
vnext_security: get_str_field(&json, "scy"),
|
||||||
|
// this probably does not exist in vmess uri
|
||||||
|
sid: url_decode(get_str_field(&json, "pbk")),
|
||||||
|
// this probably does not exist in vmess uri
|
||||||
|
flow: url_decode(get_str_field(&json, "flow")),
|
||||||
|
sni: get_str_field(&json, "sni"),
|
||||||
|
fp: url_decode(get_str_field(&json, "fp")),
|
||||||
|
r#type: url_decode(get_str_field(&json, "net")),
|
||||||
|
encryption: None,
|
||||||
|
header_type: url_decode(get_str_field(&json, "type")),
|
||||||
|
host: url_decode(get_str_field(&json, "host")),
|
||||||
|
// this probably does not exist in vmess uri
|
||||||
|
seed: url_decode(get_str_field(&json, "seed")),
|
||||||
|
quic_security: None,
|
||||||
|
key: None,
|
||||||
|
mode: url_decode(get_str_field(&json, "type")),
|
||||||
|
service_name: url_decode(get_str_field(&json, "path")),
|
||||||
|
// this probably does not exist in vmess uri
|
||||||
|
slpn: url_decode(get_str_field(&json, "slpn")),
|
||||||
|
// this probably does not exist in vmess uri
|
||||||
|
spx: url_decode(get_str_field(&json, "spx")),
|
||||||
|
// this probably does not exist in vmess uri
|
||||||
|
extra: url_decode(get_str_field(&json, "extra")),
|
||||||
|
// this probably does not exist in vmess uri
|
||||||
|
allowInsecure: None,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_str_field(json: &Value, field: &str) -> Option<String> {
|
||||||
|
return json.get(field).and_then(|v| v.as_str()).map(String::from);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_raw_data_from_uri(uri: &str) -> RawData {
|
||||||
|
let data = uri.split_once("vmess://").unwrap().1;
|
||||||
let query_and_name = uri.split_once("?").unwrap().1;
|
let query_and_name = uri.split_once("?").unwrap().1;
|
||||||
|
|
||||||
let raw_query = query_and_name
|
let raw_query = query_and_name
|
||||||
.split_once("#")
|
.split_once("#")
|
||||||
.unwrap_or((query_and_name, ""))
|
.unwrap_or((query_and_name, ""))
|
||||||
@@ -35,6 +94,7 @@ pub fn get_data(uri: &str) -> RawData {
|
|||||||
key: get_parameter_value(&query, "key"),
|
key: get_parameter_value(&query, "key"),
|
||||||
mode: url_decode(get_parameter_value(&query, "mode")),
|
mode: url_decode(get_parameter_value(&query, "mode")),
|
||||||
service_name: url_decode(get_parameter_value(&query, "serviceName")),
|
service_name: url_decode(get_parameter_value(&query, "serviceName")),
|
||||||
|
vnext_security: None,
|
||||||
slpn: get_parameter_value(&query, "slpn"),
|
slpn: get_parameter_value(&query, "slpn"),
|
||||||
spx: url_decode(get_parameter_value(&query, "spx")),
|
spx: url_decode(get_parameter_value(&query, "spx")),
|
||||||
extra: url_decode(get_parameter_value(&query, "extra")),
|
extra: url_decode(get_parameter_value(&query, "extra")),
|
||||||
@@ -45,7 +105,7 @@ pub fn get_data(uri: &str) -> RawData {
|
|||||||
fn parse_vmess_address(raw_data: &str) -> VmessAddress {
|
fn parse_vmess_address(raw_data: &str) -> VmessAddress {
|
||||||
let (uuid, raw_address): (String, &str) = match raw_data.split_once("@") {
|
let (uuid, raw_address): (String, &str) = match raw_data.split_once("@") {
|
||||||
None => {
|
None => {
|
||||||
panic!("Wrong vmess format, no `@` found in the address");
|
panic!("Wrong vmess format, no `@` found in the address and it was not a valid base64");
|
||||||
}
|
}
|
||||||
Some(data) => (String::from(data.0), data.1),
|
Some(data) => (String::from(data.0), data.1),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ pub fn create_outbound_settings(data: &RawData) -> OutboundSettings {
|
|||||||
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"))),
|
||||||
level: Some(0),
|
level: Some(0),
|
||||||
|
security: data.vnext_security.clone(),
|
||||||
}]),
|
}]),
|
||||||
}],
|
}],
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user