commit d4ec353a8f75f9710b92dfb40e3b05ec3f0888d5
parent b26b80c16ae2fa1317f41f2c30da47c695fcc5c9
Author: lash <dev@holbrook.no>
Date: Fri, 24 Jun 2022 09:01:02 +0000
Swap request data to file to enable multiple reads
Diffstat:
4 files changed, 98 insertions(+), 35 deletions(-)
diff --git a/src/auth/pgp.rs b/src/auth/pgp.rs
@@ -1,3 +1,4 @@
+use std::io::Read;
use crate::auth::{
AuthSpec,
AuthError,
@@ -69,10 +70,10 @@ fn check_key_bundle(data: &Vec<u8>) -> Option<PublicKey> {
// None
}
-fn check_sig_single(public_key: &PublicKey, signature_data: Vec<u8>, message: Vec<u8>) -> bool {
+fn check_sig_single(public_key: &PublicKey, signature_data: Vec<u8>, mut message: impl Read, message_length: usize) -> bool {
match Signature::from_slice(Version::Old, &signature_data) {
Ok(v) => {
- match v.verify(public_key, &message[..]) {
+ match v.verify(public_key, message) {
Ok(v) => {
return true;
},
@@ -84,10 +85,12 @@ fn check_sig_single(public_key: &PublicKey, signature_data: Vec<u8>, message: Ve
false
}
-fn check_sig_bundle(public_key: &PublicKey, signature_data: Vec<u8>, message: Vec<u8>) -> bool {
+fn check_sig_bundle(public_key: &PublicKey, signature_data: Vec<u8>, mut message: impl Read, message_length: usize) -> bool {
match StandaloneSignature::from_bytes(&signature_data[..]) {
Ok(v) => {
- match v.verify(public_key, &message[..]) {
+ let mut data: Vec<u8> = vec!();
+ let r = message.read_to_end(&mut data);
+ match v.verify(public_key, &data) {
Ok(v) => {
return true;
},
@@ -99,28 +102,47 @@ fn check_sig_bundle(public_key: &PublicKey, signature_data: Vec<u8>, message: Ve
false
}
-pub fn auth_check(auth: &AuthSpec) -> Result<AuthResult, AuthError> {
+pub fn auth_check(auth: &AuthSpec, data: impl Read, data_length: usize) -> Result<AuthResult, AuthError> {
if auth.method != "pgp" {
return Err(AuthError{});
}
+
let key_data = match base64::decode(&auth.key) {
Ok(v) => {
- debug!("found valid raw key");
v
},
Err(e) => {
return Err(AuthError{});
}
};
+
+ let sig_data = match base64::decode(&auth.signature) {
+ Ok(v) => {
+ v
+ },
+ Err(e) => {
+ return Err(AuthError{});
+ }
+ };
+
let key = match check_key_single(&key_data) {
Some(v) => {
+ if !check_sig_single(&v, sig_data, data, data_length) {
+ error!("invalid raw signature for {:?}", hex::encode(&v.fingerprint()));
+ return Err(AuthError{});
+ }
+ debug!("found valid raw key {:?}", hex::encode(&v.fingerprint()));
v
},
None => {
let key = match check_key_bundle(&key_data) {
Some(v) => {
- debug!("found valid key bundle");
+ if !check_sig_bundle(&v, sig_data, data, data_length) {
+ error!("invalid bundle signature for {:?}", hex::encode(&v.fingerprint()));
+ return Err(AuthError{});
+ }
+ debug!("found valid key bundle {:?}", hex::encode(&v.fingerprint()));
v
},
None => {
@@ -131,8 +153,6 @@ pub fn auth_check(auth: &AuthSpec) -> Result<AuthResult, AuthError> {
},
};
- println!("key {:?}", key);
-
let res = AuthResult {
identity: key.fingerprint(),
@@ -169,9 +189,10 @@ mod tests {
let auth_spec_str = format!("pgp:{}:{}", key_single_base64, sig_foo_single_base64);
let auth_spec = AuthSpec::from_str(&auth_spec_str).unwrap();
+ let data = b"foo";
let r = match check_key_single(&key_single) {
Some(v) => {
- if !check_sig_single(&v, sig_foo_single, b"foo".to_vec()) {
+ if !check_sig_single(&v, sig_foo_single, &data[..], 0) {
panic!("invalid");
}
},
@@ -194,9 +215,11 @@ mod tests {
let sig_foo_bundle = hex::decode(&sig_foo_bundle_hex).unwrap();
let sig_foo_bundle_base64 = base64::encode(&sig_foo_bundle);
+ let data = b"foo";
+
let r = match check_key_bundle(&key_bundle) {
Some(v) => {
- if !check_sig_bundle(&v, sig_foo_bundle, b"foo".to_vec()) {
+ if !check_sig_bundle(&v, sig_foo_bundle, &data[..], 0) {
panic!("invalid");
}
},
@@ -221,7 +244,9 @@ mod tests {
let auth_spec_str = format!("pgp:{}:{}", key_single_base64, sig_foo_single_base64);
let auth_spec = AuthSpec::from_str(&auth_spec_str).unwrap();
- match auth_check(&auth_spec) {
+ let data = b"foo";
+
+ match auth_check(&auth_spec, &data[..], 0) {
Ok(v) => {
},
Err(e) => {
@@ -244,7 +269,9 @@ mod tests {
let auth_spec_str = format!("pgp:{}:{}", key_bundle_base64, sig_foo_bundle_base64);
let auth_spec = AuthSpec::from_str(&auth_spec_str).unwrap();
- match auth_check(&auth_spec) {
+ let data = b"foo";
+
+ match auth_check(&auth_spec, &data[..], 0) {
Ok(v) => {
},
Err(e) => {
diff --git a/src/main.rs b/src/main.rs
@@ -4,6 +4,8 @@ use tiny_http::{
Request,
Response,
StatusCode,
+ Header,
+ Method,
};
use std::net::{Ipv4Addr, SocketAddrV4};
use std::str::FromStr;
@@ -11,6 +13,12 @@ use std::path::{PathBuf, Path};
use std::fs::File;
use std::error::Error;
use std::fmt;
+use std::io::{
+ copy as io_copy,
+ Read,
+ Seek,
+ empty,
+};
use env_logger;
@@ -31,7 +39,7 @@ use request::process_method;
use log::{debug, info, error};
-use tempfile::NamedTempFile;
+use tempfile::tempfile;
#[cfg(feature = "dev")]
@@ -57,7 +65,7 @@ impl fmt::Display for NoAuthError {
}
-fn exec_response(mut req: Request, r: RequestResult) {
+fn exec_response(req: Request, r: RequestResult) {
let res_status: StatusCode;
match r.typ {
RequestResultType::Found => {
@@ -108,9 +116,9 @@ fn exec_response(mut req: Request, r: RequestResult) {
}
-fn exec_auth(auth_spec: AuthSpec) -> Option<AuthResult> {
+fn exec_auth(auth_spec: AuthSpec, data: impl Read, data_length: usize) -> Option<AuthResult> {
#[cfg(feature = "dev")]
- match mock_auth_check(&auth_spec) {
+ match mock_auth_check(&auth_spec, data, data_length) {
Ok(v) => {
return Some(v);
},
@@ -119,7 +127,7 @@ fn exec_auth(auth_spec: AuthSpec) -> Option<AuthResult> {
}
#[cfg(feature = "pgpauth")]
- match pgp_auth_check(&auth_spec) {
+ match pgp_auth_check(&auth_spec, data, data_length) {
Ok(v) => {
return Some(v);
},
@@ -131,7 +139,7 @@ fn exec_auth(auth_spec: AuthSpec) -> Option<AuthResult> {
}
-fn process_auth(auth_spec: AuthSpec) -> Option<AuthResult> {
+fn process_auth(auth_spec: AuthSpec, data: impl Read, data_length: usize) -> Option<AuthResult> {
if !auth_spec.valid() {
let r = AuthResult{
identity: vec!(),
@@ -139,12 +147,12 @@ fn process_auth(auth_spec: AuthSpec) -> Option<AuthResult> {
};
return Some(r);
}
- exec_auth(auth_spec)
+ exec_auth(auth_spec, data, data_length)
}
-fn auth_from_headers(req: &Request) -> Option<AuthSpec> {
- for h in req.headers() {
+fn auth_from_headers(headers: &[Header], method: &Method) -> Option<AuthSpec> {
+ for h in headers {
let k = &h.field;
if k.equiv("Authorization") {
let v = &h.value;
@@ -155,7 +163,6 @@ fn auth_from_headers(req: &Request) -> Option<AuthSpec> {
},
Err(e) => {
error!("malformed auth string: {}", &h.value);
- let method = req.method();
let r = AuthSpec{
method: String::from(method.as_str()),
key: String::new(),
@@ -170,12 +177,15 @@ fn auth_from_headers(req: &Request) -> Option<AuthSpec> {
}
-fn process_request(mut req: &Request) -> AuthResult {
+fn process_request(req: &mut Request, f: &File) -> AuthResult {
+ let headers = req.headers();
+ let method = req.method();
+
let r: Option<AuthResult>;
- r = match auth_from_headers(req) {
+ r = match auth_from_headers(headers, method) {
Some(v) => {
- process_auth(v)
+ process_auth(v, f, 0)
},
_ => {
None
@@ -196,6 +206,7 @@ fn process_request(mut req: &Request) -> AuthResult {
}
}
+
fn main() {
env_logger::init();
@@ -221,9 +232,6 @@ fn main() {
}
};
- let res = process_request(&req);
-
- let mut path = base_path.clone();
let url = String::from(&req.url()[1..]);
let method = req.method().clone();
@@ -236,9 +244,35 @@ fn main() {
},
};
let f = req.as_reader();
+ let mut path = base_path.clone();
+ let mut res: AuthResult = AuthResult{
+ identity: vec!(),
+ error: false,
+ };
+ let rw: Option<File> = match tempfile() {
+ Ok(mut v) => {
+ io_copy(f, &mut v);
+ v.rewind();
+ res = process_request(&mut req, &mut v);
+ v.rewind();
+ Some(v)
+ },
+ Err(e) => {
+ None
+ },
+ };
+
+ let mut result: RequestResult;
+ match rw {
+ Some(v) => {
+ result = process_method(&method, url, v, expected_size, &path, res);
+ },
+ None => {
+ let v = empty();
+ result = process_method(&method, url, v, expected_size, &path, res);
+ },
+ };
- let mut result = process_method(&method, url, f, expected_size, &path, res);
-
exec_response(req, result);
}
}
diff --git a/src/record.rs b/src/record.rs
@@ -174,10 +174,10 @@ pub fn put_immutable(path: &Path, mut f: impl Read, expected_size: usize) -> Res
}
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);
let link_path_buf = path.join(&mutable_ref);
+
+ let record = put_immutable(path, f, expected_size);
match record {
Ok(v) => {
symlink(&v.path, &link_path_buf);
diff --git a/src/request.rs b/src/request.rs
@@ -21,6 +21,7 @@ use std::io::Read;
use log::{
debug,
+ error,
};
pub fn process_method(method: &Method, url: String, mut f: impl Read, expected_size: usize, path: &Path, auth_result: AuthResult) -> RequestResult {
@@ -36,7 +37,7 @@ pub fn process_method(method: &Method, url: String, mut f: impl Read, expected_s
if auth_result.active() {
let res: RequestResult;
let rk = ResourceKey::from_str(url.as_str()).unwrap();
- debug!("authenticated as {:?} using mutable key {} -> {}", auth_result, &url, &rk);
+ debug!("mutable put, authenticated as {:?} using mutable key {} -> {}", auth_result, &url, &rk);
let ptr = rk.pointer_for(&auth_result);
match put_mutable(ptr, path, f, expected_size) {
Ok(v) => {
@@ -48,7 +49,8 @@ pub fn process_method(method: &Method, url: String, mut f: impl Read, expected_s
};
},
Err(e) => {
- let err_str = format!("{}", e);
+ let err_str = format!("{:?}", e);
+ error!("{}", err_str);
res = RequestResult {
typ: RequestResultType::RecordError,
v: Some(String::from(err_str)),