@ -1,6 +1,7 @@
use std ::path ::Path ;
use chrono ::{ DateTime , Duration , Utc } ;
use num_traits ::ToPrimitive ;
use rocket ::form ::Form ;
use rocket ::fs ::NamedFile ;
use rocket ::fs ::TempFile ;
@ -8,17 +9,17 @@ use rocket::serde::json::Json;
use serde_json ::Value ;
use crate ::{
api ::{ ApiResult , EmptyResult , JsonResult , JsonUpcase , Notify , NumberOrString , UpdateType } ,
api ::{ ApiResult , EmptyResult , JsonResult , JsonUpcase , Notify , UpdateType } ,
auth ::{ ClientIp , Headers , Host } ,
db ::{ models ::* , DbConn , DbPool } ,
util ::SafeString ,
util ::{ NumberOrString , SafeString } ,
CONFIG ,
} ;
const SEND_INACCESSIBLE_MSG : & str = "Send does not exist or is no longer available" ;
// The max file size allowed by Bitwarden clients and add an extra 5% to avoid issues
const SIZE_525_MB : u 64 = 550_502_400 ;
const SIZE_525_MB : i 64 = 550_502_400 ;
pub fn routes ( ) -> Vec < rocket ::Route > {
routes ! [
@ -216,30 +217,40 @@ async fn post_send_file(data: Form<UploadData<'_>>, headers: Headers, mut conn:
} = data . into_inner ( ) ;
let model = model . into_inner ( ) . data ;
let Some ( size ) = data . len ( ) . to_i64 ( ) else {
err ! ( "Invalid send size" ) ;
} ;
if size < 0 {
err ! ( "Send size can't be negative" )
}
enforce_disable_hide_email_policy ( & model , & headers , & mut conn ) . await ? ;
let size_limit = match CONFIG . user_attachment_limit ( ) {
let size_limit = match CONFIG . user_send _limit ( ) {
Some ( 0 ) = > err ! ( "File uploads are disabled" ) ,
Some ( limit_kb ) = > {
let left = ( limit_kb * 1024 ) - Attachment ::size_by_user ( & headers . user . uuid , & mut conn ) . await ;
let already_used = Send ::size_by_user ( & headers . user . uuid , & mut conn ) . await ;
let left = limit_kb . checked_mul ( 1024 ) . and_then ( | l | l . checked_sub ( already_used ) ) ;
let Some ( left ) = left else {
err ! ( "Send size overflow" ) ;
} ;
if left < = 0 {
err ! ( "Attachment storage limit reached! Delete some attachments to free up space" )
err ! ( "Send storage limit reached! Delete some send s to free up space" )
}
std ::cmp ::Ord ::max ( left as u64 , SIZE_525_MB )
i64 ::clamp ( left , 0 , SIZE_525_MB )
}
None = > SIZE_525_MB ,
} ;
if size > size_limit {
err ! ( "Send storage limit exceeded with this file" ) ;
}
let mut send = create_send ( model , headers . user . uuid ) ? ;
if send . atype ! = SendType ::File as i32 {
err ! ( "Send content is not a file" ) ;
}
let size = data . len ( ) ;
if size > size_limit {
err ! ( "Attachment storage limit exceeded with this file" ) ;
}
let file_id = crate ::crypto ::generate_send_id ( ) ;
let folder_path = tokio ::fs ::canonicalize ( & CONFIG . sends_folder ( ) ) . await ? . join ( & send . uuid ) ;
let file_path = folder_path . join ( & file_id ) ;
@ -253,7 +264,7 @@ async fn post_send_file(data: Form<UploadData<'_>>, headers: Headers, mut conn:
if let Some ( o ) = data_value . as_object_mut ( ) {
o . insert ( String ::from ( "Id" ) , Value ::String ( file_id ) ) ;
o . insert ( String ::from ( "Size" ) , Value ::Number ( size . into ( ) ) ) ;
o . insert ( String ::from ( "SizeName" ) , Value ::String ( crate ::util ::get_display_size ( size as i32 ) ) ) ;
o . insert ( String ::from ( "SizeName" ) , Value ::String ( crate ::util ::get_display_size ( size ) ) ) ;
}
send . data = serde_json ::to_string ( & data_value ) ? ;
@ -285,24 +296,31 @@ async fn post_send_file_v2(data: JsonUpcase<SendData>, headers: Headers, mut con
enforce_disable_hide_email_policy ( & data , & headers , & mut conn ) . await ? ;
let file_length = match & data . FileLength {
Some ( m ) = > Some ( m . into_i32 ( ) ? ) ,
_ = > None ,
Some ( m ) = > m . into_i64 ( ) ? ,
_ = > err ! ( "Invalid send length" ) ,
} ;
if file_length < 0 {
err ! ( "Send size can't be negative" )
}
let size_limit = match CONFIG . user_attachment_limit ( ) {
let size_limit = match CONFIG . user_send _limit ( ) {
Some ( 0 ) = > err ! ( "File uploads are disabled" ) ,
Some ( limit_kb ) = > {
let left = ( limit_kb * 1024 ) - Attachment ::size_by_user ( & headers . user . uuid , & mut conn ) . await ;
let already_used = Send ::size_by_user ( & headers . user . uuid , & mut conn ) . await ;
let left = limit_kb . checked_mul ( 1024 ) . and_then ( | l | l . checked_sub ( already_used ) ) ;
let Some ( left ) = left else {
err ! ( "Send size overflow" ) ;
} ;
if left < = 0 {
err ! ( "Attachment storage limit reached! Delete some attachments to free up space" )
err ! ( "Send storage limit reached! Delete some send s to free up space" )
}
std ::cmp ::Ord ::max ( left as u64 , SIZE_525_MB )
i64 ::clamp ( left , 0 , SIZE_525_MB )
}
None = > SIZE_525_MB ,
} ;
if file_length . is_some ( ) & & file_length . unwrap ( ) as u64 > size_limit {
err ! ( "Attachment storage limit exceeded with this file" ) ;
if file_length > size_limit {
err ! ( "Send storage limit exceeded with this file" ) ;
}
let mut send = create_send ( data , headers . user . uuid ) ? ;
@ -312,8 +330,8 @@ async fn post_send_file_v2(data: JsonUpcase<SendData>, headers: Headers, mut con
let mut data_value : Value = serde_json ::from_str ( & send . data ) ? ;
if let Some ( o ) = data_value . as_object_mut ( ) {
o . insert ( String ::from ( "Id" ) , Value ::String ( file_id . clone ( ) ) ) ;
o . insert ( String ::from ( "Size" ) , Value ::Number ( file_length . unwrap ( ) . into ( ) ) ) ;
o . insert ( String ::from ( "SizeName" ) , Value ::String ( crate ::util ::get_display_size ( file_length . unwrap ( ) ) ) ) ;
o . insert ( String ::from ( "Size" ) , Value ::Number ( file_length . into ( ) ) ) ;
o . insert ( String ::from ( "SizeName" ) , Value ::String ( crate ::util ::get_display_size ( file_length ) ) ) ;
}
send . data = serde_json ::to_string ( & data_value ) ? ;
send . save ( & mut conn ) . await ? ;