Skip to content
Snippets Groups Projects
Unverified Commit 8dccdf32 authored by huntr.dev | the place to protect open source's avatar huntr.dev | the place to protect open source Committed by GitHub
Browse files

Merge pull request #1 from doshmajhan/master

Generate CSRF token when upload feature enabled
parents f932a3cc 6b192690
No related branches found
No related tags found
No related merge requests found
......@@ -7,3 +7,6 @@
# These are backup files generated by rustfmt
**/*.rs.bk
# IDE folders
.idea/
......@@ -89,6 +89,11 @@ name = "cfg-if"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "chrono"
version = "0.4.13"
......@@ -206,6 +211,16 @@ dependencies = [
"wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "getrandom"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.72 (registry+https://github.com/rust-lang/crates.io-index)",
"wasi 0.10.2+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "groupable"
version = "0.2.0"
......@@ -639,6 +654,17 @@ dependencies = [
"rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.72 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_chacha 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_hc 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_chacha"
version = "0.1.1"
......@@ -657,6 +683,15 @@ dependencies = [
"rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_chacha"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"ppv-lite86 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_core"
version = "0.3.1"
......@@ -678,6 +713,14 @@ dependencies = [
"getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_core"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"getrandom 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_hc"
version = "0.1.0"
......@@ -694,6 +737,14 @@ dependencies = [
"rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_hc"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rand_core 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_isaac"
version = "0.1.1"
......@@ -853,6 +904,7 @@ dependencies = [
"path-dedot 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
"percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"pretty-bytes 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)",
"termcolor 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)",
"url 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
......@@ -1047,6 +1099,11 @@ name = "wasi"
version = "0.9.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "wasi"
version = "0.10.2+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "winapi"
version = "0.3.9"
......@@ -1089,6 +1146,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
"checksum cc 1.0.58 (registry+https://github.com/rust-lang/crates.io-index)" = "f9a06fb2e53271d7c279ec1efea6ab691c35a2ae67ec0d91d7acec0caf13b518"
"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
"checksum cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
"checksum chrono 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)" = "c74d84029116787153e02106bf53e66828452a4b325cc8652b788b5967c0a0b6"
"checksum chunked_transfer 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "498d20a7aaf62625b9bf26e637cf7736417cde1d0c99f1d04d1170229a85cf87"
"checksum clap 2.33.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bdfa80d47f954d53a35a64987ca1422f495b8d6483c0fe9f7117b36c2a792129"
......@@ -1103,6 +1161,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
"checksum getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)" = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5"
"checksum getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb"
"checksum getrandom 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8"
"checksum groupable 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "32619942b8be646939eaf3db0602b39f5229b74575b67efc897811ded1db4e57"
"checksum hermit-abi 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "3deed196b6e7f9e44a2ae8d94225d80302d81208b1bb673fd21fe634645c85a9"
"checksum htmlescape 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e9025058dae765dee5070ec375f591e2ba14638c63feff74f13805a72e523163"
......@@ -1152,13 +1211,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum quick-error 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
"checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca"
"checksum rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
"checksum rand 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e"
"checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef"
"checksum rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
"checksum rand_chacha 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d"
"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
"checksum rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc"
"checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
"checksum rand_core 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7"
"checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4"
"checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
"checksum rand_hc 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73"
"checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08"
"checksum rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b"
"checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071"
......@@ -1201,6 +1264,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum vec_map 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
"checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd"
"checksum version_check 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed"
"checksum wasi 0.10.2+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
"checksum wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
"checksum winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
......
......@@ -18,6 +18,7 @@ chrono = "0.4.9"
flate2 = "1.0.11"
filetime = "0.2.7"
pretty-bytes = "0.2.2"
rand = "0.8.3"
url = "2.1.0"
hyper-native-tls = {version = "0.3.0", optional=true}
mime_guess = "2.0"
......
......@@ -18,7 +18,7 @@ FLAGS:
--norange Disable header::Range support (partial request)
--nosort Disable directory entries sort (by: name, modified, size)
-s, --silent Disable all outputs
-u, --upload Enable upload files (multiple select)
-u, --upload Enable upload files (multiple select) (CSRF token required)
-V, --version Prints version information
OPTIONS:
......@@ -80,6 +80,7 @@ simple-http-server -h
- [Range, If-Range, If-Match] => [Content-Range, 206, 416]
- [x] (default disabled) Automatic render index page [index.html, index.htm]
- [x] (default disabled) Upload file
- A CSRF token is generated when upload is enabled and must be sent as a parameter when uploading a file
- [x] (default disabled) HTTP Basic Authentication (by username:password)
- [x] Sort by: filename, filesize, modifled
- [x] HTTPS support
......
......@@ -27,6 +27,8 @@ use open;
use path_dedot::ParseDot;
use percent_encoding::percent_decode;
use pretty_bytes::converter::convert;
use rand::distributions::Alphanumeric;
use rand::{thread_rng, Rng};
use termcolor::{Color, ColorSpec};
use color::{build_spec, Printer};
......@@ -69,7 +71,7 @@ fn main() {
.arg(clap::Arg::with_name("upload")
.short("u")
.long("upload")
.help("Enable upload files (multiple select)"))
.help("Enable upload files. (multiple select) (CSRF token required)"))
.arg(clap::Arg::with_name("redirect").long("redirect")
.takes_value(true)
.validator(|url_string| iron::Url::parse(url_string.as_str()).map(|_| ()))
......@@ -209,7 +211,7 @@ fn main() {
.map(|s| PathBuf::from(s).canonicalize().unwrap())
.unwrap_or_else(|| env::current_dir().unwrap());
let index = matches.is_present("index");
let upload = matches.is_present("upload");
let upload_arg = matches.is_present("upload");
let redirect_to = matches
.value_of("redirect")
.map(iron::Url::parse)
......@@ -261,10 +263,22 @@ fn main() {
let silent = matches.is_present("silent");
let upload: Option<Upload> = if upload_arg {
let token: String = thread_rng()
.sample_iter(&Alphanumeric)
.take(10)
.map(char::from)
.collect();
Some(Upload { csrf_token: token })
} else {
None
};
if !silent {
printer
.println_out(
r#" Index: {}, Upload: {}, Cache: {}, Cors: {}, Range: {}, Sort: {}, Threads: {}
r#" Index: {}, Cache: {}, Cors: {}, Range: {}, Sort: {}, Threads: {}
Upload: {}, CSRF Token: {}
Auth: {}, Compression: {}
https: {}, Cert: {}, Cert-Password: {}
Root: {},
......@@ -273,12 +287,18 @@ fn main() {
======== [{}] ========"#,
&vec![
enable_string(index),
enable_string(upload),
enable_string(cache),
enable_string(cors),
enable_string(range),
enable_string(sort),
threads.to_string(),
enable_string(upload_arg),
(if upload.is_some() {
upload.as_ref().unwrap().csrf_token.as_str()
} else {
""
})
.to_string(),
auth.unwrap_or("disabled").to_string(),
compression_string,
(if cert.is_some() {
......@@ -381,11 +401,14 @@ fn main() {
std::process::exit(1);
};
}
struct Upload {
csrf_token: String,
}
struct MainHandler {
root: PathBuf,
index: bool,
upload: bool,
upload: Option<Upload>,
cache: bool,
range: bool,
redirect_to: Option<iron::Url>,
......@@ -433,7 +456,7 @@ impl Handler for MainHandler {
));
}
if self.upload && req.method == method::Post {
if self.upload.is_some() && req.method == method::Post {
if let Err((s, msg)) = self.save_files(req, &fs_path) {
return Ok(error_resp(s, &msg));
} else {
......@@ -485,26 +508,62 @@ impl MainHandler {
// in a new temporary directory under the OS temporary directory.
match multipart.save().size_limit(self.upload_size_limit).temp() {
SaveResult::Full(entries) => {
for (_, fields) in entries.fields {
for field in fields {
let mut data = field.data.readable().unwrap();
let headers = &field.headers;
let mut target_path = path.clone();
target_path.push(headers.filename.clone().unwrap());
if let Err(errno) = std::fs::File::create(target_path)
.and_then(|mut file| io::copy(&mut data, &mut file))
{
return Err((
status::InternalServerError,
format!("Copy file failed: {}", errno),
));
} else {
println!(
" >> File saved: {}",
headers.filename.clone().unwrap()
);
}
// Pull out csrf field to check if token matches one generated
let csrf_field = match entries
.fields
.get("csrf")
.map(|fields| fields.first())
.unwrap_or(None)
{
Some(field) => field,
None => {
return Err((
status::BadRequest,
String::from("csrf parameter not provided"),
))
}
};
// Read token value from field
let mut token = String::new();
csrf_field
.data
.readable()
.unwrap()
.read_to_string(&mut token)
.unwrap();
// Check if they match
if self.upload.as_ref().unwrap().csrf_token != token {
return Err((
status::BadRequest,
String::from("csrf token does not match"),
));
}
// Grab all the fields named files
let files_fields = match entries.fields.get("files") {
Some(fields) => fields,
None => {
return Err((status::BadRequest, String::from("no files provided")))
}
};
for field in files_fields {
let mut data = field.data.readable().unwrap();
let headers = &field.headers;
let mut target_path = path.clone();
target_path.push(headers.filename.clone().unwrap());
if let Err(errno) = std::fs::File::create(target_path)
.and_then(|mut file| io::copy(&mut data, &mut file))
{
return Err((
status::InternalServerError,
format!("Copy file failed: {}", errno),
));
} else {
println!(" >> File saved: {}", headers.filename.clone().unwrap());
}
}
Ok(())
......@@ -738,16 +797,18 @@ impl MainHandler {
));
}
// Optinal upload form
let upload_form = if self.upload {
// Optional upload form
let upload_form = if self.upload.is_some() {
format!(
r#"
<form style="margin-top:1em; margin-bottom:1em;" action="/{path}" method="POST" enctype="multipart/form-data">
<input type="file" name="files" accept="*" multiple />
<input type="hidden" name="csrf" value="{csrf}"/>
<input type="submit" value="Upload" />
</form>
"#,
path = encode_link_path(path_prefix)
path = encode_link_path(path_prefix),
csrf = self.upload.as_ref().unwrap().csrf_token
)
} else {
"".to_owned()
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment