2023-09-30 11:26:47 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
forms.rs - All the forms
|
|
|
|
*/
|
|
|
|
|
2023-10-01 10:41:34 +02:00
|
|
|
use std::collections::HashMap;
|
2023-09-30 11:26:47 +02:00
|
|
|
|
2023-10-01 04:05:08 +02:00
|
|
|
use askama::Template;
|
2023-10-01 04:05:39 +02:00
|
|
|
use warp::{Filter, reply::Reply, reject::Rejection, filters::multipart::FormData, http::StatusCode};
|
2023-09-30 11:26:47 +02:00
|
|
|
use futures_util::TryStreamExt;
|
|
|
|
use bytes::BufMut;
|
2023-10-01 06:44:19 +02:00
|
|
|
use serde::Serialize;
|
|
|
|
|
2023-10-13 01:25:51 +02:00
|
|
|
use crate::files::{File, lookup::LookupKind, DeleteMode};
|
2023-09-30 11:26:47 +02:00
|
|
|
|
2023-10-13 15:37:18 +02:00
|
|
|
use super::{state::SharedState, pages::{BadActionReq, UploadSuccessPage, self}, rejection::HttpReject};
|
2023-10-01 02:14:35 +02:00
|
|
|
|
2023-10-13 15:37:18 +02:00
|
|
|
#[derive(Debug, Serialize, Clone)]
|
2023-10-01 06:44:19 +02:00
|
|
|
struct FormElement {
|
|
|
|
data: Vec<u8>,
|
|
|
|
mime: String
|
|
|
|
}
|
2023-10-01 10:40:37 +02:00
|
|
|
impl FormElement {
|
|
|
|
pub fn as_str_or_reject(self: &Self) -> Result<String, Rejection> {
|
|
|
|
Ok(String::from_utf8(self.data.clone()).map_err(|err| warp::reject::custom(HttpReject::FromUtf8Error(err)))?)
|
|
|
|
}
|
|
|
|
}
|
2023-10-01 06:44:19 +02:00
|
|
|
|
2023-10-01 10:40:37 +02:00
|
|
|
pub async fn upload(form: FormData, state: SharedState) -> Result<Box<dyn Reply>, Rejection> {
|
2023-09-30 11:26:47 +02:00
|
|
|
|
2023-10-01 06:44:19 +02:00
|
|
|
let params: HashMap<String, FormElement> = form.and_then(|mut field| async move {
|
2023-09-30 11:26:47 +02:00
|
|
|
let mut bytes: Vec<u8> = vec![];
|
|
|
|
while let Some(byte) = field.data().await {
|
|
|
|
bytes.put(byte.unwrap())
|
|
|
|
}
|
|
|
|
|
2023-10-01 06:44:19 +02:00
|
|
|
Ok((field.name().into(), FormElement { data: bytes, mime: field.content_type().unwrap_or("text/plain").to_string() }))
|
2023-10-01 04:05:08 +02:00
|
|
|
}).try_collect()
|
|
|
|
.await
|
|
|
|
.map_err(|err| warp::reject::custom(HttpReject::WarpError(err.into())))?;
|
|
|
|
|
|
|
|
// check that required fields exist
|
|
|
|
let mut all_exist = true;
|
2023-10-01 06:44:19 +02:00
|
|
|
let _ = vec!["delmode", "file", "filename", "password"].iter().for_each(|x| {
|
2023-10-01 04:05:08 +02:00
|
|
|
let field = x.to_string();
|
|
|
|
if ! params.contains_key(&field) {
|
|
|
|
all_exist = false;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
if ! all_exist {
|
|
|
|
return Ok(Box::new(
|
|
|
|
warp::reply::with_status(
|
|
|
|
warp::reply::html(
|
2023-10-01 13:45:12 +02:00
|
|
|
BadActionReq {
|
2023-10-20 17:49:36 +02:00
|
|
|
env: state.env.clone(),
|
|
|
|
conf: state.config.clone()
|
2023-10-01 13:45:12 +02:00
|
|
|
}
|
2023-10-01 04:05:08 +02:00
|
|
|
.render()
|
|
|
|
.map_err(|err| warp::reject::custom(HttpReject::AskamaError(err.into())))?
|
|
|
|
),
|
|
|
|
StatusCode::BAD_REQUEST
|
|
|
|
)
|
|
|
|
))
|
|
|
|
}
|
2023-09-30 11:26:47 +02:00
|
|
|
|
2023-10-15 09:16:08 +02:00
|
|
|
let check_off = FormElement { data: "off".as_bytes().to_vec(), mime: "text/plain".into() };
|
|
|
|
|
2023-10-01 06:44:19 +02:00
|
|
|
let data = params.get("file").unwrap();
|
2023-10-13 01:25:51 +02:00
|
|
|
let delmode = params.get("delmode").unwrap();
|
2023-10-01 06:44:19 +02:00
|
|
|
let named = params.get("named");
|
|
|
|
let filename = params.get("filename").unwrap();
|
2023-10-13 15:37:18 +02:00
|
|
|
let tos_check = match params.get("tos_consent") {
|
|
|
|
Some(v) => (*v).clone(),
|
2023-10-15 09:16:08 +02:00
|
|
|
None => check_off.clone()
|
|
|
|
};
|
|
|
|
|
|
|
|
let protected = params.get("passworded").unwrap_or(&check_off.clone()).as_str_or_reject()?;
|
|
|
|
let protected = protected == "on";
|
|
|
|
let password: Option<String> = {
|
|
|
|
let pass = params.get("password");
|
|
|
|
if protected && pass.is_some() {
|
|
|
|
Some(pass.unwrap().as_str_or_reject()?)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
2023-10-13 15:37:18 +02:00
|
|
|
};
|
2023-10-15 09:16:08 +02:00
|
|
|
|
2023-10-01 10:40:37 +02:00
|
|
|
let mut is_named = named.is_none();
|
2023-10-13 15:37:18 +02:00
|
|
|
let tos_check = tos_check.as_str_or_reject()?;
|
|
|
|
if tos_check != "on" {
|
|
|
|
return Ok(
|
|
|
|
Box::new(
|
|
|
|
warp::reply::html(
|
|
|
|
pages::ErrorPage {
|
|
|
|
env: state.env,
|
2023-10-20 17:49:36 +02:00
|
|
|
conf: state.config.clone(),
|
2023-10-13 15:37:18 +02:00
|
|
|
error_text: "You must consent to the terms and conditions!".into(),
|
|
|
|
link: Some("/".into()),
|
|
|
|
link_text: Some("Go back".into())
|
|
|
|
}
|
|
|
|
.render()
|
|
|
|
.map_err(
|
|
|
|
|err|
|
|
|
|
warp::reject::custom(HttpReject::AskamaError(err))
|
|
|
|
)?
|
|
|
|
)
|
|
|
|
)
|
|
|
|
)
|
|
|
|
}
|
2023-10-13 01:25:51 +02:00
|
|
|
|
|
|
|
let delmode = delmode.as_str_or_reject()?;
|
|
|
|
if delmode != "30" && delmode != "dl" {
|
|
|
|
return Err(warp::reject::custom(HttpReject::StringError("delmode is neither 30 or dl!".into())));
|
|
|
|
}
|
2023-10-01 10:40:37 +02:00
|
|
|
|
|
|
|
if named.is_some() {
|
|
|
|
is_named = named.unwrap().as_str_or_reject()? == "on";
|
|
|
|
}
|
2023-10-01 06:44:19 +02:00
|
|
|
|
|
|
|
let file = File::create(
|
|
|
|
data.data.clone(),
|
|
|
|
data.mime.clone(),
|
|
|
|
match named {
|
|
|
|
Some(named) => {
|
2023-10-01 10:40:37 +02:00
|
|
|
if named.as_str_or_reject()?
|
2023-10-01 06:44:19 +02:00
|
|
|
.to_string() == "on" {
|
2023-10-01 10:40:37 +02:00
|
|
|
Some(filename.as_str_or_reject()?)
|
2023-10-01 06:44:19 +02:00
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
},
|
|
|
|
None => None
|
|
|
|
},
|
2023-10-13 01:25:51 +02:00
|
|
|
state.env.clone(),
|
|
|
|
{
|
|
|
|
if delmode == "30" {
|
|
|
|
DeleteMode::Time
|
|
|
|
} else {
|
|
|
|
DeleteMode::TimeOrDownload
|
|
|
|
}
|
2023-10-15 09:16:08 +02:00
|
|
|
},
|
|
|
|
password
|
2023-10-01 10:40:37 +02:00
|
|
|
).await
|
|
|
|
.map_err(|err| warp::reject::custom(HttpReject::StringError(err.to_string())))?;
|
|
|
|
|
|
|
|
state.file_mgr.save(&file, {
|
|
|
|
if is_named {
|
|
|
|
LookupKind::ByName
|
|
|
|
} else {
|
|
|
|
LookupKind::ByHash
|
|
|
|
}
|
|
|
|
}).map_err(|err| warp::reject::custom(HttpReject::StringError(err.to_string())))?;
|
2023-10-01 06:44:19 +02:00
|
|
|
|
2023-10-10 13:56:28 +02:00
|
|
|
let uploaded = UploadSuccessPage {
|
|
|
|
env: state.env.clone(),
|
2023-10-20 17:49:36 +02:00
|
|
|
conf: state.config.clone(),
|
2023-10-11 15:34:19 +02:00
|
|
|
link: file.leftmost_link()
|
2023-10-10 13:56:28 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
Ok(Box::new(warp::reply::html(uploaded.render().unwrap())))
|
|
|
|
|
2023-09-30 11:26:47 +02:00
|
|
|
}
|
|
|
|
|
2023-10-01 02:14:35 +02:00
|
|
|
pub fn get_routes(state: SharedState) -> impl Filter<Extract = impl Reply, Error = Rejection> + Clone {
|
2023-09-30 11:26:47 +02:00
|
|
|
warp::post().and(
|
2023-10-01 02:14:35 +02:00
|
|
|
warp::multipart::form()
|
|
|
|
.and(warp::any().map(move || state.clone()))
|
|
|
|
.and_then(upload)
|
2023-09-30 11:26:47 +02:00
|
|
|
)
|
|
|
|
}
|