whole bunch of stuff ig

main
Zynh0722 2023-04-08 08:12:14 -07:00
parent e1c499ee72
commit 88b875b809
4 changed files with 236 additions and 19 deletions

1
.gitignore vendored
View File

@ -1 +1,2 @@
/target /target
.DS_Store

107
Cargo.lock generated
View File

@ -111,6 +111,21 @@ dependencies = [
"percent-encoding", "percent-encoding",
] ]
[[package]]
name = "futures"
version = "0.3.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40"
dependencies = [
"futures-channel",
"futures-core",
"futures-executor",
"futures-io",
"futures-sink",
"futures-task",
"futures-util",
]
[[package]] [[package]]
name = "futures-channel" name = "futures-channel"
version = "0.3.28" version = "0.3.28"
@ -118,6 +133,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2"
dependencies = [ dependencies = [
"futures-core", "futures-core",
"futures-sink",
] ]
[[package]] [[package]]
@ -126,6 +142,34 @@ version = "0.3.28"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c"
[[package]]
name = "futures-executor"
version = "0.3.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0"
dependencies = [
"futures-core",
"futures-task",
"futures-util",
]
[[package]]
name = "futures-io"
version = "0.3.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964"
[[package]]
name = "futures-macro"
version = "0.3.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.13",
]
[[package]] [[package]]
name = "futures-sink" name = "futures-sink"
version = "0.3.28" version = "0.3.28"
@ -144,10 +188,27 @@ version = "0.3.28"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533"
dependencies = [ dependencies = [
"futures-channel",
"futures-core", "futures-core",
"futures-io",
"futures-macro",
"futures-sink",
"futures-task", "futures-task",
"memchr",
"pin-project-lite", "pin-project-lite",
"pin-utils", "pin-utils",
"slab",
]
[[package]]
name = "getrandom"
version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4"
dependencies = [
"cfg-if",
"libc",
"wasi",
] ]
[[package]] [[package]]
@ -387,11 +448,15 @@ name = "nyazoom"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"axum", "axum",
"futures",
"rand",
"tokio", "tokio",
"tokio-util",
"tower", "tower",
"tower-http", "tower-http",
"tracing", "tracing",
"tracing-subscriber", "tracing-subscriber",
"urlencoding",
] ]
[[package]] [[package]]
@ -467,6 +532,12 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]]
name = "ppv-lite86"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.56" version = "1.0.56"
@ -485,6 +556,36 @@ dependencies = [
"proc-macro2", "proc-macro2",
] ]
[[package]]
name = "rand"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
dependencies = [
"libc",
"rand_chacha",
"rand_core",
]
[[package]]
name = "rand_chacha"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
dependencies = [
"ppv-lite86",
"rand_core",
]
[[package]]
name = "rand_core"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
dependencies = [
"getrandom",
]
[[package]] [[package]]
name = "redox_syscall" name = "redox_syscall"
version = "0.2.16" version = "0.2.16"
@ -842,6 +943,12 @@ version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4"
[[package]]
name = "urlencoding"
version = "2.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8db7427f936968176eaa7cdf81b7f98b980b18495ec28f1b5791ac3bfe3eea9"
[[package]] [[package]]
name = "valuable" name = "valuable"
version = "0.1.0" version = "0.1.0"

View File

@ -7,8 +7,12 @@ edition = "2021"
[dependencies] [dependencies]
axum = { version = "0.6.12", features = ["multipart", "http2"] } axum = { version = "0.6.12", features = ["multipart", "http2"] }
futures = "0.3.28"
rand = { version = "0.8.5", features = ["small_rng"] }
tokio = { version = "1.27.0", features = ["full"] } tokio = { version = "1.27.0", features = ["full"] }
tokio-util = { version = "0.7.7", features = ["io"] }
tower = { version = "0.4.13", features = ["util"] } tower = { version = "0.4.13", features = ["util"] }
tower-http = { version = "0.4.0", features = ["fs", "trace", "limit"] } tower-http = { version = "0.4.0", features = ["fs", "trace", "limit"] }
tracing = "0.1.37" tracing = "0.1.37"
tracing-subscriber = { version = "0.3.16", features = ["env-filter"] } tracing-subscriber = { version = "0.3.16", features = ["env-filter"] }
urlencoding = "2.1.2"

View File

@ -1,56 +1,161 @@
use std::io;
use std::net::SocketAddr; use std::net::SocketAddr;
use std::path::{Path, PathBuf};
use axum::body::Bytes;
use axum::http::StatusCode;
use axum::routing::post;
use axum::BoxError;
use axum::{ use axum::{
extract::{DefaultBodyLimit, Multipart}, extract::{DefaultBodyLimit, Multipart},
response::{IntoResponse, Redirect}, response::Redirect,
Router, Router,
}; };
use axum::routing::post; use futures::{Stream, TryStreamExt};
use rand::distributions::{Alphanumeric, DistString};
use rand::rngs::SmallRng;
use rand::SeedableRng;
use tokio::fs::File;
use tokio::io::BufWriter;
use tokio_util::io::StreamReader;
use tower_http::{limit::RequestBodyLimitLayer, services::ServeDir, trace::TraceLayer}; use tower_http::{limit::RequestBodyLimitLayer, services::ServeDir, trace::TraceLayer};
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt}; use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
#[tokio::main] #[tokio::main]
async fn main() { async fn main() -> io::Result<()> {
tracing_subscriber::registry() tracing_subscriber::registry()
.with( .with(
tracing_subscriber::EnvFilter::try_from_default_env() tracing_subscriber::EnvFilter::try_from_default_env()
.unwrap_or_else(|_| "nyazoo=debug,tower_http=debug".into()), .unwrap_or_else(|_| "nyazoom=debug,tower_http=debug".into()),
) )
.with(tracing_subscriber::fmt::layer()) .with(tracing_subscriber::fmt::layer())
.init(); .init();
// uses create_dir_all to create both .cache and .temp inside it in one go
make_dir(".cache/.temp").await?;
// Router Setup
let with_big_body = Router::new() let with_big_body = Router::new()
.route("/upload", post(upload)) .route("/upload", post(upload))
.layer(DefaultBodyLimit::disable()) .layer(DefaultBodyLimit::disable())
.layer(RequestBodyLimitLayer::new( .layer(RequestBodyLimitLayer::new(
250 * 1024 * 1024, // 250Mb 10 * 1024 * 1024 * 1024, // 10GiB
)); ));
let base = Router::new().nest_service("/", ServeDir::new("dist")); let base = Router::new()
.nest_service("/", ServeDir::new("dist"))
.nest_service("/download", ServeDir::new(".cache"));
let app = Router::new().merge(with_big_body).merge(base); let app = Router::new()
.merge(with_big_body)
.merge(base)
.layer(TraceLayer::new_for_http());
// Server creation
let addr = SocketAddr::from(([0, 0, 0, 0], 3000)); let addr = SocketAddr::from(([0, 0, 0, 0], 3000));
tracing::debug!("listening on {}", addr); tracing::debug!("listening on {}", addr);
axum::Server::bind(&addr) axum::Server::bind(&addr)
.serve(app.layer(TraceLayer::new_for_http()).into_make_service()) .serve(app.into_make_service())
.await .await
.unwrap(); .unwrap();
Ok(())
} }
async fn upload(mut body: Multipart) -> impl IntoResponse { async fn upload(mut body: Multipart) -> Result<Redirect, (StatusCode, String)> {
while let Some(field) = body.next_field().await.unwrap() { let cache_folder = Path::new(".cache/.temp").join(get_random_name(10));
let name = field.name().unwrap().to_string();
let content_type = field.content_type().unwrap().to_string();
let file_name = field.file_name().unwrap().to_string();
let data = field.bytes().await.unwrap();
tracing::debug!( make_dir(&cache_folder)
"\n\nLength of {name} ({file_name}: {content_type}) is {} bytes\n", .await
data.len() .map_err(|err| (StatusCode::INTERNAL_SERVER_ERROR, err.to_string()))?;
)
while let Some(field) = body.next_field().await.unwrap() {
let file_name = if let Some(file_name) = field.file_name() {
file_name.to_owned()
} else {
continue;
};
if !path_is_valid(&file_name) {
return Err((StatusCode::BAD_REQUEST, "Invalid Filename >:(".to_owned()))
}
let path = cache_folder.join(file_name);
tracing::debug!("\n\nstuff written to {path:?}\n");
stream_to_file(&path, field).await?
} }
Redirect::to("/") tracing::debug!("{cache_folder:?}");
Ok(Redirect::to("/"))
}
async fn stream_to_file<S, E, P>(path: P, stream: S) -> Result<(), (StatusCode, String)>
where
P: AsRef<Path>,
S: Stream<Item = Result<Bytes, E>>,
E: Into<BoxError>,
{
async {
// Convert the stream into an `AsyncRead`.
let body_with_io_error = stream.map_err(|err| io::Error::new(io::ErrorKind::Other, err));
let body_reader = StreamReader::new(body_with_io_error);
futures::pin_mut!(body_reader);
// Create the file. `File` implements `AsyncWrite`.
let mut file = BufWriter::new(File::create(&path).await?);
// Copy the body into the file.
tokio::io::copy(&mut body_reader, &mut file).await?;
io::Result::Ok(())
}
.await
.map_err(|err| (StatusCode::INTERNAL_SERVER_ERROR, err.to_string()))
}
async fn remove_dir<T>(folder: T) -> io::Result<()>
where
T: AsRef<Path>,
{
tokio::fs::remove_dir_all(&folder).await?;
Ok(())
}
#[inline]
fn path_is_valid(path: &str) -> bool {
let mut components = Path::new(path).components().peekable();
if let Some(first) = components.peek() {
tracing::debug!("{:?}", &first);
if !matches!(first, std::path::Component::Normal(_)) {
return false;
}
}
components.count() == 1
}
#[inline]
async fn make_dir<T>(name: T) -> io::Result<()>
where
T: AsRef<Path>,
{
tokio::fs::create_dir_all(name)
.await
.or_else(|err| match err.kind() {
io::ErrorKind::AlreadyExists => Ok(()),
_ => Err(err),
})
}
#[inline]
fn get_random_name(len: usize) -> String {
let mut rng = SmallRng::from_entropy();
Alphanumeric.sample_string(&mut rng, len)
} }