Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions singbox/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@ log = "0.4"
pretty_env_logger = "0.5"
chrono = "0.4"
semver = "1.0"
urlencoding = "2.1.3"
2 changes: 2 additions & 0 deletions singbox/src/error/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ pub enum ConversionError {
InvalidDnsObject,
MissingServersArray,
MissingTypeField,
UnsupportedShadowsocks,
Other(String),
}

Expand Down Expand Up @@ -54,6 +55,7 @@ impl fmt::Display for ConversionError {
write!(f, "Missing or invalid 'servers' array in DNS configuration")
}
Self::MissingTypeField => write!(f, "Missing type field"),
Self::UnsupportedShadowsocks => write!(f, "Unsupported Shadowsocks"),
Self::Other(e) => write!(f, "{}", e),
}
}
Expand Down
32 changes: 27 additions & 5 deletions singbox/src/protocol/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,12 +86,34 @@

fn parse_shadowsocks(data: &str) -> Result<Self, ConversionError> {
let url = Url::parse(&format!("ss://{}", data)).map_err(|_| ConversionError::InvalidUri)?;

let mut password = url.password().map(|p| p.to_string());
let mut method = url.username().to_string();

// If no password was provided, try to decode the method.
if password.is_none() {
let decrypted = match general_purpose::STANDARD.decode(&method) {
Ok(decoded_bytes) => match String::from_utf8(decoded_bytes) {
Ok(decoded_str) => decoded_str,
Err(_) => method.to_string(),
},
Err(_) => method.to_string(),
};
let decrypted_arr: Vec<&str> = decrypted.split(':').collect();
if decrypted_arr.len() > 1 {
method = decrypted_arr[0].to_string();
password = Some(decrypted_arr[1..].join(":"));
} else {
return Err(ConversionError::UnsupportedShadowsocks);
}
}
let password = password.unwrap();

Ok(Self::Shadowsocks {
method: url.username().to_string(),
password: url
.password()
.ok_or(ConversionError::MissingPassword)?
.to_string(),
method,
password: urlencoding::decode(&password)
.map_err(|_| ConversionError::FailedDecode)?
.into_owned(),
host: url
.host_str()
.ok_or(ConversionError::MissingHost)?
Expand Down Expand Up @@ -374,7 +396,7 @@
let host = query
.remove("host")
.map(|h| h.split(',').map(|s| s.trim().to_string()).collect())
.unwrap_or_else(Vec::new);

Check warning on line 399 in singbox/src/protocol/mod.rs

View workflow job for this annotation

GitHub Actions / clippy

use of `unwrap_or_else` to construct default value

warning: use of `unwrap_or_else` to construct default value --> singbox/src/protocol/mod.rs:399:18 | 399 | .unwrap_or_else(Vec::new); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_or_default = note: `#[warn(clippy::unwrap_or_default)]` on by default

let path = query
.remove("path")
Expand Down
Loading