wala-rust

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

commit 66cb14f5a0c749e49cfa44e192d7495c46f585f2
parent 70ea818eae929cec6425f0f632ade5731058c611
Author: lash <dev@holbrook.no>
Date:   Thu, 23 Jun 2022 05:17:11 +0000

Refactor request handling for clarify, implement mutable put

Diffstat:
Msrc/auth/mock.rs | 1+
Msrc/auth/mod.rs | 18++++++++++++++++++
Msrc/auth/pgp.rs | 1+
Msrc/main.rs | 277++++++++++++++++++++++++++++++++++++-------------------------------------------
Dsrc/mutable.rs | 1-
Msrc/record.rs | 61++++++++++++++++++++++++++++++++++++++++++-------------------
6 files changed, 188 insertions(+), 171 deletions(-)

diff --git a/src/auth/mock.rs b/src/auth/mock.rs @@ -14,6 +14,7 @@ pub fn auth_check(auth: &AuthSpec) -> Result<AuthResult, AuthError> { } let res = AuthResult{ identity: auth.key.as_bytes().to_vec(), + error: false, }; Ok(res) } diff --git a/src/auth/mod.rs b/src/auth/mod.rs @@ -4,6 +4,7 @@ use std::fmt; pub struct AuthResult { pub identity: Vec<u8>, + pub error: bool, } pub struct AuthSpec { @@ -12,6 +13,22 @@ pub struct AuthSpec { pub signature: String, } +impl AuthSpec { + pub fn valid(&self) -> bool { + self.key.len() > 0 + } +} + +impl AuthResult { + pub fn active(&self) -> bool { + self.identity.len() > 0 + } + + pub fn valid(&self) -> bool { + !self.error + } +} + #[derive(Debug)] pub struct AuthSpecError; @@ -27,6 +44,7 @@ impl fmt::Display for AuthSpecError { } } + impl FromStr for AuthSpec { type Err = AuthSpecError; diff --git a/src/auth/pgp.rs b/src/auth/pgp.rs @@ -49,6 +49,7 @@ pub fn auth_check(auth: &AuthSpec) -> Result<AuthResult, AuthError> { let res = AuthResult { identity: key.fingerprint(), + error: false, }; Ok(res) } diff --git a/src/main.rs b/src/main.rs @@ -4,29 +4,31 @@ use tiny_http::{ Request, Response, StatusCode, - Method, }; use std::net::{Ipv4Addr, SocketAddrV4}; use std::str::FromStr; use std::path::{PathBuf, Path}; use std::fs::File; -use std::fmt::Error; +use std::error::Error; +use std::fmt; use env_logger; mod auth; -mod record; - use auth::{ AuthSpec, AuthResult, }; + +mod record; use record::{ - put_immutable, - RequestError, - RequestErrorType, + RequestResult, + RequestResultType, }; +mod request; +use request::process_method; + use log::{debug, info, error}; use tempfile::NamedTempFile; @@ -38,6 +40,50 @@ use crate::auth::mock::auth_check as mock_auth_check; #[cfg(feature = "pgpauth")] use crate::auth::pgp::auth_check as pgp_auth_check; + +#[derive(Debug)] +pub struct NoAuthError; + +impl Error for NoAuthError { + fn description(&self) -> &str{ + "no auth" + } +} + +impl fmt::Display for NoAuthError { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.write_str(self.description()) + } +} + + +fn exec_response(mut req: Request, r: RequestResult) { + let res_status: StatusCode; + match r.typ { + RequestResultType::WriteError => { + res_status = StatusCode(500); + }, + RequestResultType::AuthError => { + res_status = StatusCode(403); + }, + RequestResultType::InputError => { + res_status = StatusCode(400); + }, + _ => { + res_status = StatusCode(500); + }, + } + match r.v { + Some(v) => { + req.respond(Response::from_string(v)); + }, + None => { + req.respond(Response::empty(res_status)); + } + } +} + + fn exec_auth(auth_spec: AuthSpec) -> Option<AuthResult> { #[cfg(feature = "dev")] match mock_auth_check(&auth_spec) { @@ -61,29 +107,69 @@ fn exec_auth(auth_spec: AuthSpec) -> Option<AuthResult> { } -fn exec_error(e: RequestError, req: Request) { - let res_status: StatusCode; - match e.typ { - RequestErrorType::WriteError => { - res_status = StatusCode(500); - }, - RequestErrorType::AuthError => { - res_status = StatusCode(403); - }, - RequestErrorType::FormatError => { - res_status = StatusCode(400); +fn process_auth(auth_spec: AuthSpec) -> Option<AuthResult> { + if !auth_spec.valid() { + let r = AuthResult{ + identity: vec!(), + error: true, + }; + return Some(r); + } + exec_auth(auth_spec) +} + + +fn auth_from_headers(req: &Request) -> Option<AuthSpec> { + 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) => { + return Some(v); + }, + Err(e) => { + error!("malformed auth string: {}", &h.value); + let method = req.method(); + let r = AuthSpec{ + method: String::from(method.as_str()), + key: String::new(), + signature: String::new(), + }; + return Some(r); + } + } + } + } + None +} + + +fn process_request(mut req: &Request) -> AuthResult { + let r: Option<AuthResult>; + + r = match auth_from_headers(req) { + Some(v) => { + process_auth(v) }, _ => { - res_status = StatusCode(500); + None }, - } - match e.v { + }; + + match r { Some(v) => { - req.respond(Response::from_string(v)); + return v; }, - None => { - req.respond(Response::empty(res_status)); - } + _ => {}, + }; + + // is not auth + AuthResult{ + identity: vec!(), + error: false, } } @@ -102,9 +188,9 @@ fn main() { let srv = Server::new(srv_cfg).unwrap(); loop { - let r = srv.recv(); + let b = srv.recv(); let mut req: Request; - match r { + match b { Ok(v) => req = v, Err(e) => { error!("{}", e); @@ -112,135 +198,24 @@ fn main() { } }; - let mut res_status: StatusCode; - - let mut auth_spec: Option<AuthSpec> = None; - let mut is_auth = false; - let mut is_signed: Option<AuthResult> = None; - - 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) => { - auth_spec = Some(v); - }, - Err(e) => { - error!("malformed auth string: {}", &h.value); - } - } - } - } - - 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 res = process_request(&req); - let url = &req.url()[1..]; let mut path = base_path.clone(); - - match req.method() { - Method::Put => { - match is_signed { - Some(v) => { - res_status = StatusCode(403); - let mut res = Response::empty(res_status); - req.respond(res); - continue; - }, - _ => {}, - } - }, - Method::Get => { - let path_base = path.join(url); - let path_maybe: Option<PathBuf>; - let path_maybe = match path_base.canonicalize() { - Ok(v) => { - Some(v) - }, - Err(e) => { - None - }, - }; - - match path_maybe { - Some(v) => { - match File::open(v) { - Ok(f) => { - res_status = StatusCode(200); - let mut res = Response::from_file(f); - req.respond(res); - continue; - }, - Err(e) => { - res_status = StatusCode(404); - let mut res = Response::empty(res_status); - req.respond(res); - continue; - }, - } - }, - None => { - 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()); - - let hash: String; - let mut total_size: usize = 0; + let url = String::from(req.url()); + let method = req.method().clone(); 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; - }, - }; - + Some(v) => { + v + }, + None => { + 0 + }, + }; let f = req.as_reader(); - match put_immutable(&path, f, expected_size) { - Ok(v) => { - hash = hex::encode(v.digest); - }, - Err(e) => { - exec_error(e, req); - continue; - }, - } - res_status = StatusCode(200); - let mut res = Response::from_string(hash); - res = res.with_status_code(res_status); - req.respond(res); + let mut result = process_method(&method, url, f, expected_size, &path, res); + + exec_response(req, result); } } diff --git a/src/mutable.rs b/src/mutable.rs @@ -1 +0,0 @@ - diff --git a/src/record.rs b/src/record.rs @@ -17,32 +17,35 @@ use sha2::{Sha256, Digest}; use std::fmt; use crate::auth::AuthResult; - +use tiny_http::Request; use tempfile::NamedTempFile; use log::{debug, info, error}; #[derive(Debug)] -pub enum RequestErrorType { +pub enum RequestResultType { + Found, + Changed, ReadError, WriteError, AuthError, - FormatError, + InputError, + RecordError, } #[derive(Debug)] -pub struct RequestError { - pub typ: RequestErrorType, +pub struct RequestResult { + pub typ: RequestResultType, pub v: Option<String>, } -impl fmt::Display for RequestError { +impl fmt::Display for RequestResult { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.write_str(self.description()) } } -impl Error for RequestError { +impl Error for RequestResult { fn description(&self) -> &str { match &self.v { Some(v) => { @@ -87,14 +90,13 @@ impl ResourceKey { } -pub fn put_immutable(path: &Path, mut f: impl Read, expected_size: usize) -> Result<Record, RequestError> { +pub fn put_immutable(path: &Path, mut f: impl Read, expected_size: usize) -> Result<Record, RequestResult> { let z: Vec<u8>; let hash: String; let mut total_size: usize = 0; let tempfile = match NamedTempFile::new() { Ok(of) => { -// debug!("writing to tempfile {:?} expected size {}", of.path(), expected_size); - debug!("writing to tempfile {:?}", of.path()); + debug!("writing to tempfile {:?} expected size {}", of.path(), expected_size); let mut buf: [u8; 65535] = [0; 65535]; let mut h = Sha256::new(); loop { @@ -110,8 +112,8 @@ pub fn put_immutable(path: &Path, mut f: impl Read, expected_size: usize) -> Res }, Err(e) => { error!("cannot read from request body: {}", e); - let err = RequestError{ - typ: RequestErrorType::ReadError, + let err = RequestResult{ + typ: RequestResultType::ReadError, v: None, }; return Err(err); @@ -121,8 +123,8 @@ pub fn put_immutable(path: &Path, mut f: impl Read, expected_size: usize) -> Res if expected_size > 0 { if expected_size != total_size { - let err = RequestError{ - typ: RequestErrorType::ReadError, + let err = RequestResult{ + typ: RequestResultType::ReadError, v: None, }; return Err(err); @@ -135,8 +137,8 @@ pub fn put_immutable(path: &Path, mut f: impl Read, expected_size: usize) -> Res of }, Err(e) => { - let err = RequestError{ - typ: RequestErrorType::WriteError, + let err = RequestResult{ + typ: RequestResultType::WriteError, v: None, }; return Err(err); @@ -154,7 +156,7 @@ pub fn put_immutable(path: &Path, mut f: impl Read, expected_size: usize) -> Res Ok(r) } -pub fn put_mutable(pointer: Vec<u8>, path: &Path, mut f: impl Read, expected_size: usize) -> Result<Record, RequestError> { +pub fn put_mutable(pointer: Vec<u8>, path: &Path, mut f: impl Read, expected_size: usize) -> Result<Record, RequestResult> { let record = put_immutable(path, f, expected_size); let mutable_ref = hex::encode(&pointer); @@ -174,6 +176,26 @@ pub fn put_mutable(pointer: Vec<u8>, path: &Path, mut f: impl Read, expected_siz } } +pub fn get(pointer: Vec<u8>, path: &Path) -> Option<impl Read> { + let path_canon = match path.canonicalize() { + Ok(v) => { + v + }, + Err(e) => { + return None; + }, + }; + match File::open(path_canon) { + Ok(f) => { + return Some(f); + }, + _ => {}, + } + None + + +} + #[cfg(test)] mod tests { use super::ResourceKey; @@ -196,6 +218,7 @@ mod tests { }; let subject = AuthResult{ identity: vec!(0x62, 0x61, 0x72), + error: false, }; let r = resource.pointer_for(&subject); @@ -207,7 +230,7 @@ mod tests { fn test_immutable() { let d = tempdir().unwrap(); let b = b"foo"; - put_immutable(d.path(), &b[..], 3); + put_immutable(d.path().clone(), &b[..], 3); let immutable_path_buf = d.path().join("2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae"); let immutable_path = immutable_path_buf.as_path(); @@ -226,7 +249,7 @@ mod tests { let d = tempdir().unwrap(); let b = b"foo"; let ptr = b"foobar"; - put_mutable(ptr.to_vec(), d.path(), &b[..], 3); + put_mutable(ptr.to_vec(), d.path().clone(), &b[..], 3); let foobar_hex = hex::encode(ptr); let mutable_path_buf = d.path().join(foobar_hex);