mirror of
https://github.com/uditkarode/bml-proxy.git
synced 2025-04-20 01:27:06 +00:00
164 lines
4.4 KiB
Rust
164 lines
4.4 KiB
Rust
pub mod utils;
|
|
|
|
use curl::easy::{Easy, List};
|
|
use std::env::var;
|
|
use std::io::Read;
|
|
use std::str::from_utf8;
|
|
use std::{error::Error, net::SocketAddr};
|
|
use unicase::Ascii;
|
|
use warp::hyper::HeaderMap;
|
|
use warp::{http::Method, http::Response, hyper::body::Bytes, path::FullPath, Filter};
|
|
|
|
const FOR_COPY: [&'static str; 1] = ["Content-Type"];
|
|
|
|
const BASE: &str = "https://www.bankofmaldives.com.mv/internetbanking/api/";
|
|
const ERR: &str = "{ \"code\": 407, \"message\": \"Proxy failed\" }";
|
|
|
|
fn get_base_url() -> String {
|
|
match var("BML_PROXY_BASE") {
|
|
Ok(base) => base,
|
|
Err(_) => BASE.to_string(),
|
|
}
|
|
}
|
|
|
|
fn get_proxied_body(
|
|
uri: &String,
|
|
method: &Method,
|
|
headers: &HeaderMap,
|
|
body: &Bytes,
|
|
base: &String,
|
|
) -> Result<(String, Vec<String>), Box<dyn Error>> {
|
|
let mut handle = Easy::new();
|
|
handle.url(format!("{}{}", base, uri).as_str())?;
|
|
|
|
let mut custom_headers = List::new();
|
|
for (name, value) in headers.iter() {
|
|
if FOR_COPY.iter().any(|v| Ascii::new(v) == &name) {
|
|
match value.to_str() {
|
|
Ok(val) => custom_headers.append(format!("{}: {}", name.as_str(), val).as_str())?,
|
|
Err(_) => (),
|
|
};
|
|
}
|
|
}
|
|
handle.http_headers(custom_headers)?;
|
|
|
|
let body = std::str::from_utf8(body)?;
|
|
let mut body_bytes = body.as_bytes();
|
|
|
|
if method == Method::POST {
|
|
handle.post_field_size(body_bytes.len() as u64)?;
|
|
}
|
|
|
|
let mut body_buffer = Vec::new();
|
|
let mut headers = Vec::new();
|
|
|
|
{
|
|
let mut transfer = handle.transfer();
|
|
|
|
if method == Method::POST {
|
|
transfer.read_function(|into| {
|
|
let read = body_bytes.read(into).unwrap_or(0);
|
|
Ok(read)
|
|
})?;
|
|
}
|
|
|
|
transfer.write_function(|data| {
|
|
body_buffer.extend_from_slice(data);
|
|
Ok(data.len())
|
|
})?;
|
|
|
|
transfer.header_function(|header| {
|
|
match from_utf8(header) {
|
|
Ok(v) => headers.push(v.to_string()),
|
|
Err(_) => (),
|
|
}
|
|
|
|
true
|
|
})?;
|
|
|
|
transfer.perform()?;
|
|
}
|
|
|
|
let cloned_buf = body_buffer.clone();
|
|
let s = from_utf8(&cloned_buf)?;
|
|
|
|
Ok((s.to_string(), headers))
|
|
}
|
|
|
|
fn handler(
|
|
uri: FullPath,
|
|
headers: HeaderMap,
|
|
method: Method,
|
|
body: Bytes,
|
|
ip: Option<SocketAddr>,
|
|
base: String,
|
|
) -> Result<Response<String>, warp::http::Error> {
|
|
let uri = uri.as_str().clone().to_string();
|
|
let ip_str = match ip {
|
|
Some(v) => format!("{}", v),
|
|
None => "unknown".to_string(),
|
|
};
|
|
|
|
println!("({}) {}", ip_str, uri);
|
|
|
|
let proxy_response = get_proxied_body(&uri, &method, &headers, &body, &base);
|
|
|
|
let (res, headers) = match proxy_response {
|
|
Ok(v) => v,
|
|
Err(e) => {
|
|
println!("error: {}", e);
|
|
(ERR.to_string(), vec![])
|
|
}
|
|
};
|
|
|
|
let mut builder = Response::builder();
|
|
|
|
for header in headers.iter() {
|
|
let split: Vec<&str> = header.split(": ").collect();
|
|
if split.len() == 2 {
|
|
builder = builder.header(split[0], split[1].replace("\r\n", ""));
|
|
}
|
|
}
|
|
|
|
builder.body(res)
|
|
}
|
|
|
|
#[tokio::main]
|
|
async fn main() {
|
|
let proxy_handler = warp::any()
|
|
.and(utils::extract_request_data_filter())
|
|
.and(warp::filters::addr::remote())
|
|
.and(warp::any().map(move || get_base_url()))
|
|
.map(handler);
|
|
|
|
let log_warning = || {
|
|
println!("This binary is meant to be used with LD_PRELOAD=\"/path/to/libcurl-impersonate-chrome.so\"");
|
|
println!("If you're on Arch Linux, this library can be obtained via the AUR package 'libcurl-impersonate-bin'");
|
|
println!(
|
|
"A common location for this library is '/usr/local/lib/libcurl-impersonate-chrome.so'"
|
|
);
|
|
println!("\n[WARN] proceeding without libcurl-impersonate, expect cloudflare blockages\n");
|
|
};
|
|
|
|
match var("LD_PRELOAD") {
|
|
Ok(v) => {
|
|
if !v.contains("libcurl-impersonate-chrome.so") {
|
|
log_warning();
|
|
}
|
|
}
|
|
|
|
Err(_) => log_warning(),
|
|
}
|
|
|
|
let port = var("BML_PROXY_PORT")
|
|
.unwrap_or_default()
|
|
.parse::<u16>()
|
|
.unwrap_or(3030);
|
|
|
|
println!("Proxy running on port: {}", port);
|
|
println!("Proxy base URL: {}", get_base_url());
|
|
println!("Available environment variables for modification: BML_PROXY_PORT, BML_PROXY_BASE\n");
|
|
|
|
warp::serve(proxy_handler).run(([0, 0, 0, 0], port)).await;
|
|
}
|