Implement all API according to swagger spec #27
|
@ -1,9 +1,12 @@
|
|||
use std::collections::HashMap;
|
||||
use std::{collections::HashMap, net::IpAddr};
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
||||
use serde_json::json;
|
||||
use sha2::{Sha512, Digest, digest::FixedOutput};
|
||||
use warp::{reply::{Reply, with_status, json}, http::StatusCode, reject::Rejection, Filter, filters::multipart::FormData};
|
||||
use warp_real_ip::real_ip;
|
||||
|
||||
use crate::web::{state::SharedState, forms::FormElement, rejection::HttpReject, api::types::{ErrorMessage, Error}};
|
||||
use crate::{web::{state::SharedState, forms::FormElement, api::types::{ErrorMessage, Error}}, files::{File, lookup::LookupKind}};
|
||||
|
||||
use super::{is_api_pass, check_api_pass};
|
||||
|
||||
|
@ -16,6 +19,7 @@ struct UploadAPIMetadata {
|
|||
|
||||
struct UploadAPIPayload {
|
||||
file: Vec<u8>,
|
||||
file_type: String,
|
||||
instance_pass: Option<String>,
|
||||
metadata: UploadAPIMetadata
|
||||
}
|
||||
|
@ -24,6 +28,7 @@ impl Default for UploadAPIPayload {
|
|||
fn default() -> Self {
|
||||
Self {
|
||||
file: vec![],
|
||||
file_type: "application/octet-stream".into(),
|
||||
instance_pass: None,
|
||||
metadata: UploadAPIMetadata {
|
||||
sha512: "".into(),
|
||||
|
@ -56,6 +61,8 @@ impl UploadAPIPayload {
|
|||
fields_set = true;
|
||||
}
|
||||
}
|
||||
|
||||
out.file_type = file.mime.clone();
|
||||
}
|
||||
|
||||
// optional ones
|
||||
|
@ -73,7 +80,7 @@ impl UploadAPIPayload {
|
|||
}
|
||||
}
|
||||
|
||||
pub async fn upload(state: SharedState, data: FormData) -> Result<Box<dyn Reply>, Rejection> {
|
||||
pub async fn upload(state: SharedState, data: FormData, ip: Option<IpAddr>) -> Result<Box<dyn Reply>, Rejection> {
|
||||
|
||||
let data = FormElement::from_formdata(data)
|
||||
.await;
|
||||
|
@ -100,7 +107,6 @@ pub async fn upload(state: SharedState, data: FormData) -> Result<Box<dyn Reply>
|
|||
|
||||
let payload = UploadAPIPayload::from_form(data);
|
||||
if let Some(payload) = payload {
|
||||
|
||||
if is_api_pass(&state) {
|
||||
if let Err(res) = check_api_pass(
|
||||
&state,
|
||||
|
@ -113,6 +119,93 @@ pub async fn upload(state: SharedState, data: FormData) -> Result<Box<dyn Reply>
|
|||
}
|
||||
}
|
||||
|
||||
// payload is all valid and accessible at this point
|
||||
|
||||
let mut hash: Sha512 = Sha512::new();
|
||||
hash.update(&payload.file);
|
||||
|
||||
let hash = hex::encode(hash.finalize_fixed());
|
||||
if hash != payload.metadata.sha512 {
|
||||
return Ok(
|
||||
Box::new(
|
||||
with_status(
|
||||
json(
|
||||
&ErrorMessage {
|
||||
error: Error::APIError,
|
||||
details: Some("Hash does not match file".into())
|
||||
}
|
||||
),
|
||||
StatusCode::BAD_REQUEST
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
let file = File::create(
|
||||
payload.file,
|
||||
payload.file_type,
|
||||
payload.metadata.name.clone(),
|
||||
state.env,
|
||||
crate::files::DeleteMode::Time,
|
||||
payload.metadata.pass,
|
||||
ip
|
||||
).await;
|
||||
|
||||
if let Err(err) = file {
|
||||
return Ok(
|
||||
Box::new(
|
||||
with_status(
|
||||
json(
|
||||
&ErrorMessage {
|
||||
error: Error::APIError,
|
||||
details: Some(
|
||||
format!("Error while saving the file: {err}")
|
||||
)
|
||||
}
|
||||
),
|
||||
StatusCode::INTERNAL_SERVER_ERROR
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
let file = file.unwrap();
|
||||
|
||||
let saved = state.file_mgr.save(
|
||||
&file,
|
||||
match payload.metadata.name {
|
||||
Some(_) => LookupKind::ByName,
|
||||
None => LookupKind::ByHash
|
||||
}
|
||||
);
|
||||
|
||||
if let Err(err) = saved {
|
||||
return Ok(
|
||||
Box::new(
|
||||
with_status(
|
||||
json(
|
||||
&ErrorMessage {
|
||||
error: Error::APIError,
|
||||
details: Some(
|
||||
format!("Error while saving the file: {err}")
|
||||
)
|
||||
}
|
||||
),
|
||||
StatusCode::INTERNAL_SERVER_ERROR
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
return Ok(
|
||||
Box::new(
|
||||
json(
|
||||
&json!({
|
||||
"status": "OK"
|
||||
})
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
Ok(
|
||||
|
@ -129,9 +222,13 @@ pub async fn upload(state: SharedState, data: FormData) -> Result<Box<dyn Reply>
|
|||
}
|
||||
|
||||
pub fn upload_f(state: SharedState) -> impl Filter<Extract = impl Reply, Error = Rejection> + Clone {
|
||||
|
||||
let proxy = state.env.proxy_addr.clone();
|
||||
|
||||
warp::path!("api" / "files" / "upload")
|
||||
.and(warp::post())
|
||||
.map(move || state.clone())
|
||||
.and(warp::multipart::form())
|
||||
.and(real_ip(vec![proxy]))
|
||||
.and_then(upload)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue