wala-rust

Unnamed repository; edit this file 'description' to name the repository.
Info | Log | Files | Refs | README | LICENSE

commit bd9ae4e992888c0988eef55fb85196df9ca99f6e
parent d6fbeaa9b1e55c2d793289b18c69146b4a4ff8da
Author: lash <dev@holbrook.no>
Date:   Mon, 13 Jun 2022 20:14:14 +0000

Handle put by hash and get by hash

Diffstat:
MCargo.toml | 4++++
Msrc/auth/mod.rs | 4++--
Msrc/main.rs | 184++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------
3 files changed, 171 insertions(+), 21 deletions(-)

diff --git a/Cargo.toml b/Cargo.toml @@ -9,6 +9,9 @@ edition = "2021" tiny_http = "^0.7.0" env_logger = "^0.9" log = "^0.4" +sha2 = "^0.10" +hex = "^0.4" +tempfile = "^3.3.0" [dependencies.pgp] version = "^0.7.2" @@ -16,3 +19,4 @@ optional = true [features] pgpauth = ["pgp"] +dev = [] diff --git a/src/auth/mod.rs b/src/auth/mod.rs @@ -56,5 +56,5 @@ impl fmt::Debug for AuthSpec { } } -#[cfg(test)] -mod mock; +#[cfg(feature = "dev")] +pub mod mock; diff --git a/src/main.rs b/src/main.rs @@ -4,9 +4,16 @@ use tiny_http::{ Request, Response, StatusCode, + Method, }; use std::net::{Ipv4Addr, SocketAddrV4}; use std::str::FromStr; +use std::path::{PathBuf, Path}; +use std::fs::copy as fs_copy; +use std::fs::File; +use std::io::Write; +use sha2::{Sha256, Digest}; + use env_logger; mod auth; @@ -15,9 +22,27 @@ use auth::AuthSpec; use log::{debug, info, error}; +use tempfile::NamedTempFile; + + +#[cfg(feature = "dev")] +use crate::auth::mock::auth_check as mock_auth_check; + +fn exec_auth(auth_spec: AuthSpec) -> bool { + #[cfg(feature = "dev")] + if mock_auth_check(auth_spec) { + return true; + } + + false +} + + fn main() { env_logger::init(); + let base_path = Path::new("."); + let ip_addr = Ipv4Addr::from_str("0.0.0.0").unwrap(); let tcp_port: u16 = 8001; let sock_addr = SocketAddrV4::new(ip_addr, tcp_port); @@ -29,7 +54,7 @@ fn main() { loop { let r = srv.recv(); - let req: Request; + let mut req: Request; match r { Ok(v) => req = v, Err(e) => { @@ -39,18 +64,20 @@ fn main() { }; let mut res_status: StatusCode; - let mut m: bool = false; let mut auth_spec: Option<AuthSpec> = None; + let mut is_auth = false; + let mut is_signed = false; + let mut is_mut = false; for h in req.headers() { let k = &h.field; if k.equiv("Authorization") { + is_auth = true; let v = &h.value; let r = AuthSpec::from_str(v.as_str()); match r { Ok(v) => { - m = true; auth_spec = Some(v); }, Err(e) => { @@ -59,26 +86,145 @@ fn main() { } } } - - match auth_spec { - Some(v) => { - debug!("have auth {:?}", v); + + + if is_auth { + match auth_spec { + Some(v) => { + debug!("have auth {:?}", v); + is_signed = exec_auth(v); + }, + None => { + debug!("invalid auth"); + res_status = StatusCode(401); + let mut res = Response::empty(res_status); + req.respond(res); + continue; + } + }; + } + + let url = &req.url()[1..]; + let path_base = base_path.clone().join(url); + let mut path = PathBuf::new(); + + match req.method() { + Method::Put => { + is_mut = true; + if !is_signed { + res_status = StatusCode(403); + let mut res = Response::empty(res_status); + req.respond(res); + continue; + } }, - None => { - debug!("no auth"); - } - }; + Method::Get => { + match path_base.canonicalize() { + Ok(v) => { + //path = v; + match File::open(v) { + Ok(f) => { + res_status = StatusCode(200); + let mut res = Response::from_file(f); + //res = res.with_status(res_status); + req.respond(res); + continue; + }, + Err(e) => { + res_status = StatusCode(404); + let mut res = Response::empty(res_status); + req.respond(res); + continue; + }, + } + }, + Err(e) => { + if !is_mut { + res_status = StatusCode(404); + let mut res = Response::empty(res_status); + req.respond(res); + continue; + } + }, + } + }, + _ => { + res_status = StatusCode(400); + let mut res = Response::empty(res_status); + req.respond(res); + continue; + }, + } + + info!("processing request {} for {} -> {}", req.method(), url, path.to_str().unwrap()); + + if is_mut { + let hash: String; + let mut total_size: usize = 0; + let expected_size = match req.body_length() { + Some(v) => { + v + }, + None => { + res_status = StatusCode(400); + let mut res = Response::empty(res_status); + req.respond(res); + continue; + }, + }; + + let tempfile = match NamedTempFile::new() { + Ok(of) => { + debug!("writing to tempfile {:?} expected size {}", of.path(), expected_size); + + let f = req.as_reader(); + let mut buf: [u8; 65535] = [0; 65535]; + let mut h = Sha256::new(); + loop { + match f.read(&mut buf[..]) { + Ok(v) => { + if v == 0 { + break; + } + total_size += v; + let data = &buf[..v]; + h.update(data); + of.as_file().write(data); + }, + Err(e) => { + error!("cannot read from request body: {}", e); + break; + }, + } + } + + if expected_size != total_size { + res_status = StatusCode(400); + let mut res = Response::empty(res_status); + req.respond(res); + continue; + } + let z = h.finalize(); + hash = hex::encode(z); + info!("have hash {} for content", hash); + of + }, + Err(e) => { + res_status = StatusCode(500); + let mut res = Response::empty(res_status); + req.respond(res); + continue; + } + }; + - if m { - res_status = StatusCode(200); - let mut res = Response::from_string("foo"); - res = res.with_status_code(res_status); - req.respond(res); - continue; + path = path.join(hash); + fs_copy(tempfile.path(), path); } - res_status = StatusCode(404); - let res = Response::empty(res_status); + res_status = StatusCode(200); + let mut res = Response::from_string("foo"); + res = res.with_status_code(res_status); req.respond(res); } }