Finished /upload endpoint
This commit is contained in:
parent
0b2a4f130e
commit
7570739ba4
40
Cargo.lock
generated
40
Cargo.lock
generated
@ -114,6 +114,7 @@ dependencies = [
|
|||||||
"matchit",
|
"matchit",
|
||||||
"memchr",
|
"memchr",
|
||||||
"mime",
|
"mime",
|
||||||
|
"multer",
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"rustversion",
|
"rustversion",
|
||||||
@ -269,6 +270,15 @@ dependencies = [
|
|||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "encoding_rs"
|
||||||
|
version = "0.8.35"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "equivalent"
|
name = "equivalent"
|
||||||
version = "1.0.1"
|
version = "1.0.1"
|
||||||
@ -572,6 +582,23 @@ dependencies = [
|
|||||||
"windows-sys",
|
"windows-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "multer"
|
||||||
|
version = "3.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "83e87776546dc87511aa5ee218730c92b666d7264ab6ed41f9d215af9cd5224b"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"encoding_rs",
|
||||||
|
"futures-util",
|
||||||
|
"http",
|
||||||
|
"httparse",
|
||||||
|
"memchr",
|
||||||
|
"mime",
|
||||||
|
"spin",
|
||||||
|
"version_check",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "object"
|
name = "object"
|
||||||
version = "0.36.4"
|
version = "0.36.4"
|
||||||
@ -830,6 +857,12 @@ dependencies = [
|
|||||||
"windows-sys",
|
"windows-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "spin"
|
||||||
|
version = "0.9.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "strsim"
|
name = "strsim"
|
||||||
version = "0.11.1"
|
version = "0.11.1"
|
||||||
@ -1032,6 +1065,7 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
"serde_yaml",
|
"serde_yaml",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
"tokio-util",
|
||||||
"tower-http",
|
"tower-http",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -1041,6 +1075,12 @@ version = "0.2.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "version_check"
|
||||||
|
version = "0.9.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasi"
|
name = "wasi"
|
||||||
version = "0.9.0+wasi-snapshot-preview1"
|
version = "0.9.0+wasi-snapshot-preview1"
|
||||||
|
@ -6,11 +6,12 @@ edition = "2021"
|
|||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
axum = "0.7.6"
|
axum = { version = "0.7.6", features = ["multipart"] }
|
||||||
clap = { version = "4.5.18", features = ["derive"] }
|
clap = { version = "4.5.18", features = ["derive"] }
|
||||||
expanduser = "1.2.2"
|
expanduser = "1.2.2"
|
||||||
if-addrs = "0.13.3"
|
if-addrs = "0.13.3"
|
||||||
serde = { version = "1.0.216", features = ["derive"] }
|
serde = { version = "1.0.216", features = ["derive"] }
|
||||||
serde_yaml = "0.9.34"
|
serde_yaml = "0.9.34"
|
||||||
tokio = { version = "1.40.0", features = ["full"] }
|
tokio = { version = "1.40.0", features = ["full"] }
|
||||||
|
tokio-util = "0.7.13"
|
||||||
tower-http = { version = "0.6.2", features = ["fs", "trace"] }
|
tower-http = { version = "0.6.2", features = ["fs", "trace"] }
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use std::{io, fs};
|
use std::{io, fs};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::PathBuf;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use expanduser::expanduser;
|
use expanduser::expanduser;
|
||||||
@ -12,8 +12,8 @@ pub fn load_config() -> Config {
|
|||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
download_path: PathBuf,
|
download_path: String,
|
||||||
upload_path: PathBuf,
|
upload_path: String,
|
||||||
pub web_port: u16,
|
pub web_port: u16,
|
||||||
pub shell_port: u16,
|
pub shell_port: u16,
|
||||||
shells: HashMap<String, String>
|
shells: HashMap<String, String>
|
||||||
@ -32,11 +32,11 @@ impl Config {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_download_path(&self) -> PathBuf {
|
pub fn get_download_path(&self) -> PathBuf {
|
||||||
self.download_path.clone()
|
expanduser(self.download_path.clone()).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_upload_path(&self) -> PathBuf {
|
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> {
|
pub fn get_shell<S: Into<String>>(&self, key: S) -> Option<String> {
|
||||||
|
@ -6,7 +6,7 @@ use tokio::net::TcpListener;
|
|||||||
use tower_http::services::ServeDir;
|
use tower_http::services::ServeDir;
|
||||||
use axum::{
|
use axum::{
|
||||||
middleware,
|
middleware,
|
||||||
routing::get,
|
routing::{get, post},
|
||||||
Router
|
Router
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -15,6 +15,7 @@ mod print_dir;
|
|||||||
mod config;
|
mod config;
|
||||||
mod shells;
|
mod shells;
|
||||||
mod logging;
|
mod logging;
|
||||||
|
mod upload;
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
@ -30,7 +31,7 @@ async fn main() {
|
|||||||
print_dir::print_interface(&args.interface, &port, &args.directory);
|
print_dir::print_interface(&args.interface, &port, &args.directory);
|
||||||
|
|
||||||
let app = Router::new()
|
let app = Router::new()
|
||||||
//.route("/upload", post(upload_handler))
|
.route("/upload", post(upload::upload_handler))
|
||||||
.route("/shells/:shell", get(shells::shells_handler))
|
.route("/shells/:shell", get(shells::shells_handler))
|
||||||
.nest_service("/download", ServeDir::new(conf.get_download_path()))
|
.nest_service("/download", ServeDir::new(conf.get_download_path()))
|
||||||
.nest_service("/", ServeDir::new(cwd))
|
.nest_service("/", ServeDir::new(cwd))
|
||||||
|
@ -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())
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user