From 53d7398ce218a3a91dfdba1c505275a09d5837be Mon Sep 17 00:00:00 2001 From: b1ek Date: Thu, 22 Aug 2024 12:32:09 +1000 Subject: [PATCH] feat: get stuff from X.cc.blek.codes from $DOCROOT/X --- Cargo.lock | 261 ++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 4 + src/env.rs | 17 ++- src/filegetter.rs | 52 +++++++++ src/main.rs | 15 ++- src/sni.rs | 80 ++++++++++++-- www/blek/index.html | 1 + 7 files changed, 416 insertions(+), 14 deletions(-) create mode 100644 src/filegetter.rs create mode 100644 www/blek/index.html diff --git a/Cargo.lock b/Cargo.lock index 236b7a6..b6af33e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,21 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + [[package]] name = "atomic-waker" version = "1.1.2" @@ -50,6 +65,12 @@ version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" + [[package]] name = "bytes" version = "1.7.1" @@ -69,9 +90,13 @@ dependencies = [ name = "ccDaemon" version = "0.1.0" dependencies = [ + "chrono", "http-body-util", "hyper", "hyper-util", + "mime", + "mime-sniffer", + "mime_guess", "tokio", ] @@ -81,6 +106,26 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "chrono" +version = "0.4.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits", + "wasm-bindgen", + "windows-targets", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + [[package]] name = "equivalent" version = "1.0.1" @@ -256,6 +301,40 @@ dependencies = [ "tracing", ] +[[package]] +name = "iana-time-zone" +version = "0.1.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "idna" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" +dependencies = [ + "matches", + "unicode-bidi", + "unicode-normalization", +] + [[package]] name = "indexmap" version = "2.4.0" @@ -272,6 +351,15 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +[[package]] +name = "js-sys" +version = "0.3.70" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" +dependencies = [ + "wasm-bindgen", +] + [[package]] name = "libc" version = "0.2.158" @@ -288,12 +376,50 @@ dependencies = [ "scopeguard", ] +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + +[[package]] +name = "matches" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" + [[package]] name = "memchr" version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "mime-sniffer" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e98f7cfbbaf64674624e2aa35327d75e3de8e4d1b2555ef70dcf0c107a95490" +dependencies = [ + "mime", + "url", +] + +[[package]] +name = "mime_guess" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" +dependencies = [ + "mime", + "unicase", +] + [[package]] name = "miniz_oxide" version = "0.7.4" @@ -315,6 +441,15 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + [[package]] name = "object" version = "0.36.3" @@ -353,6 +488,12 @@ dependencies = [ "windows-targets", ] +[[package]] +name = "percent-encoding" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" + [[package]] name = "pin-project" version = "1.1.5" @@ -475,6 +616,21 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "tinyvec" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + [[package]] name = "tokio" version = "1.39.3" @@ -569,12 +725,53 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" +[[package]] +name = "unicase" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" +dependencies = [ + "version_check", +] + +[[package]] +name = "unicode-bidi" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" + [[package]] name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +[[package]] +name = "unicode-normalization" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "url" +version = "1.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" +dependencies = [ + "idna", + "matches", + "percent-encoding", +] + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + [[package]] name = "want" version = "0.3.1" @@ -590,6 +787,70 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasm-bindgen" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" +dependencies = [ + "cfg-if", + "once_cell", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" + +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets", +] + [[package]] name = "windows-sys" version = "0.52.0" diff --git a/Cargo.toml b/Cargo.toml index e33acb3..9cfcbe9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,11 @@ version = "0.1.0" edition = "2021" [dependencies] +chrono = "0.4.38" http-body-util = "0.1.2" hyper = { version = "1.4.1", features = ["full"] } hyper-util = { version = "0.1.7", features = ["full"] } +mime = "0.3.17" +mime-sniffer = "0.1.2" +mime_guess = "2.0.5" tokio = { version = "1.39.3", features = ["full"] } diff --git a/src/env.rs b/src/env.rs index 6d74e76..f13f17e 100644 --- a/src/env.rs +++ b/src/env.rs @@ -1,13 +1,24 @@ -use std::{env::var, net::SocketAddr}; +use std::{env::var, net::SocketAddr, path::{Path, PathBuf}}; +#[derive(Debug, Clone)] pub struct Env { - pub listen: SocketAddr + pub listen: SocketAddr, + pub docroot: PathBuf, + pub tld: String +} + +impl Env { + pub fn get_doc_for_sni>(&self, sni: T) -> PathBuf { + self.docroot.clone().join(sni) + } } impl Default for Env { fn default() -> Self { Self { - listen: var("LISTEN").unwrap().parse().unwrap(), + listen: var("LISTEN").expect("LISTEN").parse().unwrap(), + docroot: var("DOCROOT").expect("DOCROOT").parse().unwrap(), + tld: var("CC_TLD").unwrap_or("cc.blek.codes".into()) } } } \ No newline at end of file diff --git a/src/filegetter.rs b/src/filegetter.rs new file mode 100644 index 0000000..2fcfb8f --- /dev/null +++ b/src/filegetter.rs @@ -0,0 +1,52 @@ +use std::{collections::HashMap, fs, path::PathBuf, time::Duration}; + +use chrono::{DateTime, Local}; +use mime::Mime; +use mime_sniffer::MimeTypeSnifferExt; + +#[derive(Debug, Clone)] +struct CachedFile { + pub die: DateTime, + pub data: Vec, + pub mime: Mime, +} + +#[derive(Debug, Clone)] +pub struct FileGetter { + cached_files: HashMap +} + +impl FileGetter { + pub fn new() -> Self { + Self { + cached_files: HashMap::new() + } + } + + pub fn get_file>(&mut self, file: T) -> Result, Mime)>, Box> { + let file_path: PathBuf = file.into(); + if let Some(file) = self.cached_files.get_mut(&file_path) { + file.die = Local::now() + Duration::from_secs(15); + + Ok(Some((file.data.clone(), file.mime.clone()))) + } else { + let mut file_path = file_path; + + if file_path.is_dir() { file_path = file_path.join("index.html"); } + if ! file_path.is_file() { return Ok(None) } + + let buf = fs::read(&file_path)?; + let mime = buf.sniff_mime_type_ext().unwrap_or(mime_guess::from_path(&file_path).first_or(mime::APPLICATION_OCTET_STREAM)); + + if self.cached_files.len() < 100 { + self.cached_files.insert(file_path, CachedFile { + die: Local::now() + Duration::from_secs(15), + data: buf.clone(), + mime: mime.clone() + }); + } + + Ok(Some((buf, mime))) + } + } +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index eae7c3d..17c1e22 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,11 @@ +use std::sync::Arc; + use hyper::server::conn::http1; use hyper_util::rt::TokioIo; use tokio::net::TcpListener; +use std::sync::Mutex; +mod filegetter; mod sni; mod env; @@ -12,14 +16,23 @@ async fn main() -> Result<(), Box> { println!("Running on {}", env.listen); let listener = TcpListener::bind(env.listen).await?; + let files = Arc::new(Mutex::new(filegetter::FileGetter::new())); loop { let (stream, _) = listener.accept().await?; + let client_ip = stream.peer_addr().map(|x| Some(x)).unwrap_or(None); let io = TokioIo::new(stream); - let svc = sni::SniWebsitesService {}; + let env = env.clone(); + let files = files.clone(); tokio::task::spawn(async move { + let svc = sni::SniWebsitesService { + client_ip, + env: env.clone(), + files + }; + if let Err(e) = http1::Builder::new() .serve_connection(io, svc) .await { diff --git a/src/sni.rs b/src/sni.rs index 7ed7734..84a614b 100644 --- a/src/sni.rs +++ b/src/sni.rs @@ -1,14 +1,22 @@ use std::future::Future; +use std::net::SocketAddr; use std::pin::Pin; +use std::sync::Arc; use http_body_util::Full; -use hyper::Response; +use hyper::{Response, http::response::Builder}; use hyper::{service::Service, Request}; use hyper::body::{Bytes, Incoming as IncomingBody}; +use std::sync::Mutex; -#[derive(Debug, Clone, Copy)] +use crate::env::Env; +use crate::filegetter::FileGetter; + +#[derive(Debug)] pub struct SniWebsitesService { - + pub client_ip: Option, + pub env: Env, + pub files: Arc> } impl SniWebsitesService { @@ -17,18 +25,70 @@ impl SniWebsitesService { } } +fn res_builder() -> Builder { + Response::builder() + .header("Server", "blek! CC 1.0") +} + +fn check_uri(uri: String) -> bool { + if ! uri.starts_with('/') { return false } + + for seg in uri.split("/") { + if seg.starts_with(".") { + return false + } + } + + true +} + +fn serve_file(sni: String, req: Request, env: &Env, files: Arc>) -> Response> { + let docpath = env.get_doc_for_sni(sni); + let uri = req.uri().path().to_string(); + + if ! check_uri(uri.to_string()) { + return res_builder() + .status(400) + .body(SniWebsitesService::make_body("illegal URI")) + .unwrap() + } + + let path = docpath.join(uri.trim_start_matches('/')); + let file = files.lock().unwrap().get_file(path).unwrap(); + + if let Some(file) = file { + res_builder() + .header("Content-Type", file.1.to_string()) + .body(SniWebsitesService::make_body(file.0)) + .unwrap() + } else { + res_builder() + .header("Content-Type", "text/html") + .body(SniWebsitesService::make_body("

not found!

this file is not found

")) + .unwrap() + } +} + impl Service> for SniWebsitesService { type Response = Response>; type Error = hyper::Error; type Future = Pin> + Send>>; - fn call(&self, _req: Request) -> Self::Future { - - let res = Response::builder() - .header("Server", "blek! CC 1.0") - .body(Self::make_body("miau")) - .unwrap(); - + fn call(&self, req: Request) -> Self::Future { + let res = + if let Some(sni) = req.headers().get("x-forwarded-host") { + let sni = sni.to_str().unwrap(); + let sni = sni.replace(&(".".to_string() + &self.env.tld), ""); + + serve_file(sni, req, &self.env, self.files.clone()) + } else { + res_builder() + .status(400) + .header("Content-Type", "text/plain") + .body(Self::make_body("refusing to answer to a non proxied request")) + .unwrap() + }; + Box::pin(async { Ok(res) }) } } \ No newline at end of file diff --git a/www/blek/index.html b/www/blek/index.html new file mode 100644 index 0000000..9c42a4a --- /dev/null +++ b/www/blek/index.html @@ -0,0 +1 @@ +heyo x3 \ No newline at end of file