Finished /upload endpoint

This commit is contained in:
Random936
2024-12-23 17:47:33 -08:00
parent 0b2a4f130e
commit 7570739ba4
5 changed files with 103 additions and 8 deletions

View File

@@ -1,5 +1,5 @@
use std::{io, fs};
use std::path::{Path, PathBuf};
use std::path::PathBuf;
use std::collections::HashMap;
use expanduser::expanduser;
@@ -12,8 +12,8 @@ pub fn load_config() -> Config {
#[derive(Deserialize)]
pub struct Config {
download_path: PathBuf,
upload_path: PathBuf,
download_path: String,
upload_path: String,
pub web_port: u16,
pub shell_port: u16,
shells: HashMap<String, String>
@@ -32,11 +32,11 @@ impl Config {
}
pub fn get_download_path(&self) -> PathBuf {
self.download_path.clone()
expanduser(self.download_path.clone()).unwrap()
}
pub fn get_upload_path(&self) -> PathBuf {
self.upload_path.clone()
expanduser(self.upload_path.clone()).unwrap()
}
pub fn get_shell<S: Into<String>>(&self, key: S) -> Option<String> {

View File

@@ -6,7 +6,7 @@ use tokio::net::TcpListener;
use tower_http::services::ServeDir;
use axum::{
middleware,
routing::get,
routing::{get, post},
Router
};
@@ -15,6 +15,7 @@ mod print_dir;
mod config;
mod shells;
mod logging;
mod upload;
#[tokio::main]
async fn main() {
@@ -30,7 +31,7 @@ async fn main() {
print_dir::print_interface(&args.interface, &port, &args.directory);
let app = Router::new()
//.route("/upload", post(upload_handler))
.route("/upload", post(upload::upload_handler))
.route("/shells/:shell", get(shells::shells_handler))
.nest_service("/download", ServeDir::new(conf.get_download_path()))
.nest_service("/", ServeDir::new(cwd))

View File

@@ -0,0 +1,53 @@
use std::{
fs::File,
io::{BufWriter, Write},
path::{Path, Component}
};
use axum::{
http::StatusCode,
extract::Multipart,
response::IntoResponse
};
use crate::config;
fn path_is_valid(path: &str) -> bool {
let path = Path::new(path);
let mut components = path.components().peekable();
if let Some(first) = components.peek() {
if !matches!(first, Component::Normal(_)) {
return false;
}
}
components.count() == 1
}
pub async fn upload_handler(mut multipart: Multipart) -> impl IntoResponse {
let conf = config::load_config();
while let Some(field) = multipart.next_field().await.unwrap() {
let file_name = match field.name() {
Some(file) => file.to_string(),
None => continue
};
let data = field.bytes().await.unwrap();
let path = conf.get_upload_path().join(&file_name);
if !path_is_valid(&file_name) {
return (StatusCode::FORBIDDEN, format!("Directory Traversal: {}", path.display()));
}
let Ok(file) = File::create(&path) else {
return (StatusCode::FORBIDDEN, format!("Failed to create file: {}", path.display()));
};
let mut writer = BufWriter::new(file);
if let Err(e) = writer.write_all(&data) {
return (StatusCode::INTERNAL_SERVER_ERROR, format!("An error occurred when writing to {}: {}", path.display(), e))
}
}
(StatusCode::CREATED, "Successfully uploaded file(s).".to_string())
}