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:
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);