forked from neri/datatrash
upgrade dependencies and time handling
This commit is contained in:
parent
4ea8797149
commit
1527445857
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "datatrash"
|
name = "datatrash"
|
||||||
version = "1.1.5"
|
version = "1.1.6"
|
||||||
authors = ["neri"]
|
authors = ["neri"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use std::env;
|
use std::env;
|
||||||
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
use time::ext::NumericalDuration;
|
||||||
use time::Duration;
|
use time::Duration;
|
||||||
use tokio::fs;
|
use tokio::fs;
|
||||||
|
|
||||||
|
@ -28,8 +29,8 @@ pub async fn get_config() -> Config {
|
||||||
let max_file_size = env::var("UPLOAD_MAX_BYTES")
|
let max_file_size = env::var("UPLOAD_MAX_BYTES")
|
||||||
.ok()
|
.ok()
|
||||||
.and_then(|variable| variable.parse().ok())
|
.and_then(|variable| variable.parse().ok())
|
||||||
.unwrap_or(8 * 1024 * 1024);
|
.or(Some(8 * 1024 * 1024))
|
||||||
let max_file_size = (max_file_size != 0).then(|| max_file_size);
|
.filter(|&max_file_size| max_file_size != 0);
|
||||||
|
|
||||||
let static_dir =
|
let static_dir =
|
||||||
PathBuf::from(env::var("STATIC_DIR").unwrap_or_else(|_| "./static".to_owned()));
|
PathBuf::from(env::var("STATIC_DIR").unwrap_or_else(|_| "./static".to_owned()));
|
||||||
|
@ -73,8 +74,8 @@ fn get_no_auth_limits() -> Option<NoAuthLimits> {
|
||||||
(Some(auth_password), Some(max_time), Some(large_file_max_time), Some(large_file_size)) => {
|
(Some(auth_password), Some(max_time), Some(large_file_max_time), Some(large_file_size)) => {
|
||||||
Some(NoAuthLimits {
|
Some(NoAuthLimits {
|
||||||
auth_password,
|
auth_password,
|
||||||
max_time: Duration::seconds(max_time as i64),
|
max_time: (max_time as i64).seconds(),
|
||||||
large_file_max_time: Duration::seconds(large_file_max_time as i64),
|
large_file_max_time: (large_file_max_time as i64).seconds(),
|
||||||
large_file_size,
|
large_file_size,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use sqlx::postgres::{PgPool, PgPoolOptions};
|
use sqlx::postgres::{PgPool, PgPoolOptions};
|
||||||
use std::env;
|
use std::env;
|
||||||
|
use time::ext::NumericalStdDuration;
|
||||||
|
|
||||||
pub async fn setup_db() -> PgPool {
|
pub async fn setup_db() -> PgPool {
|
||||||
let conn_url = &get_db_url();
|
let conn_url = &get_db_url();
|
||||||
|
@ -7,7 +8,7 @@ pub async fn setup_db() -> PgPool {
|
||||||
|
|
||||||
let pool = PgPoolOptions::new()
|
let pool = PgPoolOptions::new()
|
||||||
.max_connections(5)
|
.max_connections(5)
|
||||||
.acquire_timeout(std::time::Duration::from_secs(5))
|
.acquire_timeout(5.std_seconds())
|
||||||
.connect(conn_url)
|
.connect(conn_url)
|
||||||
.await
|
.await
|
||||||
.expect("could not create db pool");
|
.expect("could not create db pool");
|
||||||
|
|
|
@ -7,8 +7,8 @@ use std::path::Path;
|
||||||
use time::{Duration, OffsetDateTime};
|
use time::{Duration, OffsetDateTime};
|
||||||
use tokio::{fs::File, io::AsyncWriteExt};
|
use tokio::{fs::File, io::AsyncWriteExt};
|
||||||
|
|
||||||
const MAX_UPLOAD_SECONDS: i64 = 31 * 24 * 60 * 60;
|
const MAX_UPLOAD_DURATION: Duration = Duration::days(31);
|
||||||
const DEFAULT_UPLOAD_SECONDS: u32 = 30 * 60;
|
const DEFAULT_UPLOAD_DURATION: Duration = Duration::minutes(30);
|
||||||
|
|
||||||
pub(crate) struct UploadConfig {
|
pub(crate) struct UploadConfig {
|
||||||
pub original_name: Option<String>,
|
pub original_name: Option<String>,
|
||||||
|
@ -24,7 +24,7 @@ pub(crate) async fn parse_multipart(
|
||||||
) -> Result<UploadConfig, error::Error> {
|
) -> Result<UploadConfig, error::Error> {
|
||||||
let mut original_name: Option<String> = None;
|
let mut original_name: Option<String> = None;
|
||||||
let mut content_type: Option<Mime> = None;
|
let mut content_type: Option<Mime> = None;
|
||||||
let mut keep_for: Option<String> = None;
|
let mut keep_for_seconds: Option<String> = None;
|
||||||
let mut delete_on_download = false;
|
let mut delete_on_download = false;
|
||||||
let mut password = None;
|
let mut password = None;
|
||||||
let mut size = 0;
|
let mut size = 0;
|
||||||
|
@ -34,7 +34,7 @@ pub(crate) async fn parse_multipart(
|
||||||
let name = name.as_str();
|
let name = name.as_str();
|
||||||
match name {
|
match name {
|
||||||
"keep_for" => {
|
"keep_for" => {
|
||||||
keep_for = Some(parse_string(name, field).await?);
|
keep_for_seconds = Some(parse_string(name, field).await?);
|
||||||
}
|
}
|
||||||
"file" => {
|
"file" => {
|
||||||
let (mime, uploaded_name) = get_file_metadata(&field);
|
let (mime, uploaded_name) = get_file_metadata(&field);
|
||||||
|
@ -64,13 +64,13 @@ pub(crate) async fn parse_multipart(
|
||||||
|
|
||||||
let content_type =
|
let content_type =
|
||||||
content_type.ok_or_else(|| error::ErrorBadRequest("no content type found"))?;
|
content_type.ok_or_else(|| error::ErrorBadRequest("no content type found"))?;
|
||||||
let keep_for: u32 = keep_for
|
let keep_for = keep_for_seconds
|
||||||
.map(|k| k.parse())
|
.map(|k| k.parse())
|
||||||
.transpose()
|
.transpose()
|
||||||
.map_err(|e| error::ErrorBadRequest(format!("field keep_for is not a number: {}", e)))?
|
.map_err(|e| error::ErrorBadRequest(format!("field keep_for is not a number: {}", e)))?
|
||||||
.unwrap_or(DEFAULT_UPLOAD_SECONDS);
|
.map(Duration::seconds)
|
||||||
let valid_duration = Duration::seconds(keep_for.into());
|
.unwrap_or(DEFAULT_UPLOAD_DURATION);
|
||||||
let valid_till = OffsetDateTime::now_utc() + valid_duration;
|
let valid_till = OffsetDateTime::now_utc() + keep_for;
|
||||||
|
|
||||||
let upload_config = UploadConfig {
|
let upload_config = UploadConfig {
|
||||||
original_name,
|
original_name,
|
||||||
|
@ -79,7 +79,7 @@ pub(crate) async fn parse_multipart(
|
||||||
delete_on_download,
|
delete_on_download,
|
||||||
};
|
};
|
||||||
|
|
||||||
check_requirements(&upload_config, size, password, &valid_duration, config)?;
|
check_requirements(&upload_config, size, password, &keep_for, config)?;
|
||||||
|
|
||||||
Ok(upload_config)
|
Ok(upload_config)
|
||||||
}
|
}
|
||||||
|
@ -88,7 +88,7 @@ fn check_requirements(
|
||||||
upload_config: &UploadConfig,
|
upload_config: &UploadConfig,
|
||||||
size: u64,
|
size: u64,
|
||||||
password: Option<String>,
|
password: Option<String>,
|
||||||
valid_duration: &Duration,
|
keep_for: &Duration,
|
||||||
config: &config::Config,
|
config: &config::Config,
|
||||||
) -> Result<(), error::Error> {
|
) -> Result<(), error::Error> {
|
||||||
if let Some(original_name) = upload_config.original_name.as_ref() {
|
if let Some(original_name) = upload_config.original_name.as_ref() {
|
||||||
|
@ -97,17 +97,16 @@ fn check_requirements(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let valid_seconds = valid_duration.whole_seconds();
|
if *keep_for > MAX_UPLOAD_DURATION {
|
||||||
if valid_seconds > MAX_UPLOAD_SECONDS {
|
|
||||||
return Err(error::ErrorBadRequest(format!(
|
return Err(error::ErrorBadRequest(format!(
|
||||||
"maximum allowed validity is {} seconds, but you specified {} seconds",
|
"maximum allowed validity is {}, but you specified {}",
|
||||||
MAX_UPLOAD_SECONDS, valid_seconds
|
MAX_UPLOAD_DURATION, keep_for
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(no_auth_limits) = &config.no_auth_limits {
|
if let Some(no_auth_limits) = &config.no_auth_limits {
|
||||||
let requires_auth = valid_seconds > no_auth_limits.max_time.whole_seconds()
|
let requires_auth = *keep_for > no_auth_limits.max_time
|
||||||
|| valid_seconds > no_auth_limits.large_file_max_time.whole_seconds()
|
|| *keep_for > no_auth_limits.large_file_max_time
|
||||||
&& size > no_auth_limits.large_file_size;
|
&& size > no_auth_limits.large_file_size;
|
||||||
// hIGh sECUriTy paSsWoRD CHEck
|
// hIGh sECUriTy paSsWoRD CHEck
|
||||||
if requires_auth && password.as_ref() != Some(&no_auth_limits.auth_password) {
|
if requires_auth && password.as_ref() != Some(&no_auth_limits.auth_password) {
|
||||||
|
|
|
@ -14,11 +14,6 @@ impl KeyExtractor for ForwardedPeerIpKeyExtractor {
|
||||||
type Key = IpAddr;
|
type Key = IpAddr;
|
||||||
type KeyExtractionError = &'static str;
|
type KeyExtractionError = &'static str;
|
||||||
|
|
||||||
#[cfg(feature = "log")]
|
|
||||||
fn name(&self) -> &'static str {
|
|
||||||
"Forwarded peer IP"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn extract(&self, req: &ServiceRequest) -> Result<Self::Key, Self::KeyExtractionError> {
|
fn extract(&self, req: &ServiceRequest) -> Result<Self::Key, Self::KeyExtractionError> {
|
||||||
let forwarded_for = req.headers().get("x-forwarded-for");
|
let forwarded_for = req.headers().get("x-forwarded-for");
|
||||||
if !self.proxied && forwarded_for.is_some() {
|
if !self.proxied && forwarded_for.is_some() {
|
||||||
|
@ -44,8 +39,7 @@ impl KeyExtractor for ForwardedPeerIpKeyExtractor {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "log")]
|
fn response_error(&self, err: Self::KeyExtractionError) -> actix_web::Error {
|
||||||
fn key_name(&self, key: &Self::Key) -> Option<String> {
|
actix_web::error::ErrorUnauthorized(err.to_string())
|
||||||
Some(key.to_string())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue