@@ -22,6 +22,7 @@ use tracing::{error, info};
2222use crate :: AppState ;
2323
2424const MAX_FILE_SIZE_BYTES : usize = 1_000_000 ; // ~1 MB
25+ const ENCRYPTION_PUB_KEY_BYTE_LEN : usize = 65 ; // we use uncompressed keys
2526
2627/// For now, the only parts of the API we implement are
2728/// GET /<sha256> - get a file
@@ -63,6 +64,7 @@ pub async fn handle_upload(State(state): State<AppState>, body: Bytes) -> impl I
6364 let size = body. len ( ) ;
6465
6566 info ! ( "Upload File called for {} bytes" , size) ;
67+ // check size
6668 if size > MAX_FILE_SIZE_BYTES {
6769 return (
6870 StatusCode :: PAYLOAD_TOO_LARGE ,
@@ -74,7 +76,19 @@ pub async fn handle_upload(State(state): State<AppState>, body: Bytes) -> impl I
7476 if size == 0 {
7577 return ( StatusCode :: BAD_REQUEST , "Empty body" ) . into_response ( ) ;
7678 }
79+ // validate it's an ECIES/secp256k1 encrypted blob by checking if it starts with an ephemeral secp256k1 pub key
80+ // this is not a 100% guarantee (which is impossible), but rather a pretty reliable heuristic
81+ if size < ENCRYPTION_PUB_KEY_BYTE_LEN {
82+ error ! ( "Non-encrypted Upload rejected - not big enough" ) ;
83+ return ( StatusCode :: BAD_REQUEST , "Invalid body" ) . into_response ( ) ;
84+ }
85+ let pubkey_bytes = & body[ 0 ..ENCRYPTION_PUB_KEY_BYTE_LEN ] ;
86+ if let Err ( e) = nostr:: secp256k1:: PublicKey :: from_slice ( pubkey_bytes) {
87+ error ! ( "Non-encrypted Upload rejected: {e}" ) ;
88+ return ( StatusCode :: BAD_REQUEST , "Invalid body" ) . into_response ( ) ;
89+ }
7790
91+ // create hash
7892 let mut hash_engine = sha256:: HashEngine :: default ( ) ;
7993 if let Err ( e) = hash_engine. write_all ( & body) {
8094 error ! ( "Error while hashing {size} bytes: {e}" ) ;
@@ -88,11 +102,13 @@ pub async fn handle_upload(State(state): State<AppState>, body: Bytes) -> impl I
88102 size : size as i32 ,
89103 } ;
90104
105+ // store
91106 if let Err ( e) = state. file_store . insert ( file) . await {
92107 error ! ( "Error while storing {size} bytes with hash {hash}: {e}" ) ;
93108 return ( StatusCode :: INTERNAL_SERVER_ERROR , "INTERNAL_SERVER_ERROR" ) . into_response ( ) ;
94109 }
95110
111+ // return blob descriptor
96112 let blob_desc = BlobDescriptor :: new ( state. cfg . host_url , hash, size) . unwrap ( ) ;
97113 ( StatusCode :: OK , Json ( blob_desc) ) . into_response ( )
98114}
0 commit comments