pub mod dbg;
use std::path::PathBuf;
use rocket::{
http::Status,
outcome::Outcome,
request::{self, FromRequest, Request}
};
use base64::{engine::general_purpose, Engine as _};
pub struct ProxyHost<'r>(pub &'r str);
#[rocket::async_trait]
impl<'r> FromRequest<'r> for ProxyHost<'r> {
type Error = ();
async fn from_request(
req: &'r Request<'_>
) -> request::Outcome<Self, Self::Error> {
req
.headers()
.get_one("x-forwarded-host")
.map_or(Outcome::Error((Status::BadRequest, ())), |val| {
Outcome::Success(ProxyHost(val))
})
}
}
pub struct ProxyServer<'r>(pub &'r str);
#[rocket::async_trait]
impl<'r> FromRequest<'r> for ProxyServer<'r> {
type Error = ();
async fn from_request(
req: &'r Request<'_>
) -> request::Outcome<Self, Self::Error> {
req
.headers()
.get_one("x-forwarded-server")
.map_or(Outcome::Error((Status::BadRequest, ())), |val| {
Outcome::Success(ProxyServer(val))
})
}
}
pub struct ProxyFor<'r>(pub &'r str);
#[rocket::async_trait]
impl<'r> FromRequest<'r> for ProxyFor<'r> {
type Error = ();
async fn from_request(
req: &'r Request<'_>
) -> request::Outcome<Self, Self::Error> {
req
.headers()
.get_one("x-forwarded-for")
.map_or(Outcome::Error((Status::BadRequest, ())), |val| {
Outcome::Success(ProxyFor(val))
})
}
}
#[derive(Debug)]
pub struct AuthHdr {
pub authtype: String,
pub user: String,
pub pass: String
}
#[rocket::async_trait]
impl<'r> FromRequest<'r> for AuthHdr {
type Error = ();
async fn from_request(req: &'r Request<'_>) -> request::Outcome<Self, ()> {
let Some(s) = req.headers().get_one("authorization") else {
return Outcome::Error((Status::ProxyAuthenticationRequired, ()));
};
let Some(idx) = s.find(' ') else {
return Outcome::Error((Status::ProxyAuthenticationRequired, ()));
};
let t = &s[..idx];
let s = &s[(idx + 1)..];
let Ok(vu8) = general_purpose::STANDARD.decode(s) else {
return Outcome::Error((Status::ProxyAuthenticationRequired, ()));
};
let s = std::str::from_utf8(&vu8).unwrap();
let Some(idx) = s.find(':') else {
return Outcome::Error((Status::ProxyAuthenticationRequired, ()));
};
let user = &s[..idx];
let pass = &s[(idx + 1)..];
Outcome::Success(Self {
authtype: String::from(t),
user: String::from(user),
pass: String::from(pass)
})
}
}
#[repr(transparent)]
#[derive(Clone, Debug)]
pub struct RelRoot(pub String);
impl RelRoot {
#[must_use]
pub fn into_path(self) -> PathBuf {
PathBuf::from(self.0)
}
#[must_use]
pub fn into_inner(self) -> String {
self.0
}
pub fn path_to<P: AsRef<str>>(&self, rel: P) -> String {
if self.0.is_empty() {
rel.as_ref().to_string()
} else {
format!("{}/{}", self.0, rel.as_ref())
}
}
}
#[rocket::async_trait]
impl<'r> FromRequest<'r> for RelRoot {
type Error = ();
async fn from_request(req: &'r Request<'_>) -> request::Outcome<Self, ()> {
req.route().map_or(
Outcome::Error((Status::InternalServerError, ())),
|route| {
Outcome::Success(Self(
route
.uri
.origin
.path()
.segments()
.map(|_| "..")
.collect::<Vec<&str>>()
.join("/")
))
}
)
}
}