
    *jy7                        d Z ddlZddlZddlZddlZddlZddlm	Z	 ddl
mZmZ ddlmZmZ ddlmZ ddlmZ dez  Zd	efd
Zded	efdZd	e	fdZdeded	e	fdZdddede	dz  d	e	fdZd Zdedede	fdZd Zd Z dS )zD
Hermes Web UI -- File upload: multipart parser and upload handler.
    N)Path)MAX_UPLOAD_BYTES	STATE_DIR)jbad)get_session)safe_resolve_ws
   returnc                 B   dd l }dd lm}  |j        d|          }|st	          d          |                    d                              d                                          }|                     |          }i }i }	d|z   }
d|z   dz   }|	                    |
          }|dd          D ]o}|
                    d          }|                    d          r nAd|v rdnd	}||vr=|	                    |d          \  }}|                    d          r|d d
         }n|                    d          r
|d d         }|
                    d                              dd          }|                                                    |          }|                    dd          } |j        d|          } |j        d|          }|s"|                    d          }|r|                    d          |f|	|<   U|                    dd          ||<   q||	fS )Nr   zboundary=([^;\s]+)zNo boundary in Content-Type   "s   --s   
s   

s   

   
zutf-8replace)errorszContent-Disposition zname="([^"]*)"zfilename="([^"]*)")reemail.parserparsersearch
ValueErrorgroupstripencodereadsplitlstrip
startswithendswithdecodeHeaderParserparsestrget)rfilecontent_typecontent_length_re_epmboundaryrawfieldsfiles	delimiter
end_markerpartspartstrippedsep
header_rawbodyheader_textmsgdispname_mfile_mnames                           -/Users/bertmahoney/hermes-webui/api/upload.pyparse_multipartr?      s\   ))))))))))
(,77A 86777wwqzz$$++--H
**^
$
$CFE I!E)JIIi  Eabb	 B B;;w''u%% 	E(D00kkgd??::c1--
D==!! 	9DD]]5!! 	9D ''0077	7RR  ))+66ww,b11-t441488 	||A 	B!<<??D1E$KK;;wy;AAF4LL5=    filenamec                     t          j        ddt          |           j                  d d         }|r|                    d          dk    rt          d          |S )N[^\w.\-]_   .r   zInvalid filename)r)   subr   r=   r   r   )rA   	safe_names     r>   _sanitize_upload_namerI   :   sZ    S$x..*=>>ttDI -	,,22+,,,r@   c                      t          j        dd                                          } | r3t          |                                                                           S t          dz                                  S )a  Return the configured upload inbox root.

    Plain chat attachments are transient context for the agent, not project
    source files.  Keep them out of the active workspace by default while still
    allowing operators to move the inbox with HERMES_WEBUI_ATTACHMENT_DIR.
    HERMES_WEBUI_ATTACHMENT_DIRr   attachments)osgetenvr   r   
expanduserresolver   )overrides    r>   _attachment_rootrR   A   se     y6;;AACCH 5H~~((**22444%..000r@   
session_idrH   c                    t          |           }|                    dd           ||z                                  }|                    |          st	          d          |                                r|j        }|j        }t          dd          D ]\}|| d| | z                                  }|                    |          st	          d          |                                s|c S ]t	          d          |S )NTparentsexist_okzInvalid upload destinationr   i  -z'Too many uploads with the same filename)	_session_attachment_dirmkdirrP   is_relative_tor   existsstemsuffixrange)rS   rH   dest_dirdestr]   r^   idx	candidates           r>   _upload_destinationrd   N   s   &z22HNN4$N///y ))++Dx(( 75666{{}} 	DyD>> 	! 	!C!t$;$;c$;6$;$;;DDFFI++H55 ? !=>>>##%% !    !BCCCKr@   )rootre   c                   |pt                                                      }|t          j        ddt	          | pd                    d d         z                                  }|                    |          st          d          |S )NrC   rD   sessionx   zInvalid attachment directory)rR   rP   r)   rG   strr[   r   )rS   re   r`   s      r>   rY   rY   a   s    &$&&//11Dsw{CZ5L91M1MNNtPStTT]]__H""4(( 97888Or@   c           
      `   dd l }	 | j                            dd          }t          | j                            dd          pd          }|t          k    r#t          | ddt          dz  dz   did	
          S t          | j        ||          \  }}|                    dd          }d|vrt          | ddid
          S |d         \  }}|st          | ddid
          S 	 t          |          }	n$# t          $ r t          | ddid
          cY S w xY wt          |          }
t          ||
          }|                    |           t          j        |
          d         pd}t          | |
t          |          |                                j        ||                    d          d          S # t&          $ r+}t          | dt          |          id
          cY d }~S d }~wt(          $ r= t+          d|                                z   d           t          | ddid
          cY S w xY w)Nr   Content-Typer   Content-LengtherrorFile too large (max    MB)  statusrS   fileNo file field in request  No filename in uploadSession not found  zapplication/octet-streamzimage/)rA   pathsizemimeis_imagez[webui] upload error: TflushzUpload failed  )	tracebackheadersr%   intr   r   r?   r&   r   KeyErrorrI   rd   write_bytes	mimetypes
guess_typeri   statst_sizer    r   	Exceptionprint
format_exc)handler_tbr'   r(   r.   r/   rS   rA   
file_bytessrH   ra   r|   es                 r>   handle_uploadr   i   s   B**>2>>W_001A1EEJKK,,,Ww(`?OQU?UW[?[(`(`(`ajmnnnn'|^TTZZb11
Ww(BCCPPPP$V}* 	NWw(?@MMMM	JJ''AA 	J 	J 	JWw(;<SIIIIII	J)(33	":y99$$$#I..q1O5O!IIIIKK'11
 
   	  9 9 97CFF+C888888888 B B B&)9)99FFFF7O4SAAAAAABsW   A2F3 9AF3   F3 "C2 1F3 2DF3 DBF3 3
H-= G#H-#AH-,H-r   	workspacec           
         ddl }ddl}ddl}ddl}ddl}t          |          j        }t          |          j        }	|                                	                    d          rd}
n<|                                	                    d          rd}
nt          d|           t          ||	          }|                                rzddl}ddl}|                                r^d                    |                    |j        d	
                    }|                    |	dz   |z             }|                                ^|                    dd           g }d}	 |
dk    r|                    |                    |                     5 }|                                D ]}|                                r||j        z                                  }|                    |                                          st          d|j                   |t6          k    r!t          d|dz   dt6          dz   d          |j                            dd           |                    |          5 }t;          |d          5 }d}	 |                    |          }|snN|t?          |          z  }|t6          k    rt          dt6          dz   d          |                     |           f	 ddd           n# 1 swxY w Y   ddd           n# 1 swxY w Y   |!                    tE          |#                    |                                                               	 ddd           n# 1 swxY w Y   n#|
dk    r|                    |                    |                     5 }|$                                D ]}|%                                s||j        z                                  }|                    |                                          st          d|j                   |t6          k    r!t          d|dz   dt6          dz   d          |j                            dd           |&                    |          }|r|5 }t;          |d          5 }d}	 |                    |          }|snN|t?          |          z  }|t6          k    rt          dt6          dz   d          |                     |           f	 ddd           n# 1 swxY w Y   ddd           n# 1 swxY w Y   |!                    tE          |#                    |                                                               	 ddd           n# 1 swxY w Y   n8# tN          $ r+ 	 |(                    |d           n# tN          $ r Y nw xY w w xY wt?          |          |tE          |          dS )zExtract a zip or tar archive into the workspace.

    Returns a dict with ``extracted`` (int), ``files`` (list[str]).
    Raises ValueError on zip-slip or unsupported format.
    r   N)z.zipzip)z.tarz.tar.gzz.tgzz.tar.bz2z.tbz2z.tar.xzz.txztarzUnsupported archive format: r      )krD   TrU   zZip-slip blocked: zExtraction too large (i   z MB > z MB limit). Possible zip bomb.wbi   zExtraction too large (> )fileobjzTar-slip blocked: )ignore_errors)	extractedr/   ra   ))zipfiletarfileiorM   shutilr   r=   r]   lowerr!   r   r	   r\   stringrandomjoinchoicesdigits	with_namerZ   ZipFileBytesIOinfolistis_dirrA   rP   r[   _MAX_EXTRACTED_BYTESparentopenr   lenwriteappendri   relative_to
getmembersisfileextractfiler   rmtree)r   rA   r   r   r   r   rM   r   r=   r]   _moder`   r   r   r^   extracted_filestotal_extractedzfmembermember_pathsrcdst_chunk_sizechunktfsrc_objs                             r>   extract_archiver      s)    ,+++++++++++++++++++>>D>>Dzz||Y'' D			b	c	c DBBBCCC y$//H ?oo 	?WWV^^FMQ^??@@F))$*v*=>>H oo 	? NN4$N///OOKE>>J!7!788 ^B kkmm ^ ^F}} ! #+fo#="F"F"H"HK&55h6F6F6H6HII Q()Ofo)O)OPPP&)===(2_5S 2 23	B2 2 2  
  &,,TD,III -Ck41H1H -C&+-$'HH[$9$9E#( & %+s5zz9O.1EEE&0%:';	'J%: %: %:'" '" !"
  IIe,,,- !&- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - $**3{/F/FyGXGXGZGZ/[/[+\+\]]]]=^^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^B e^^bjj&<&<==  ^ mmoo ^ ^F!==?? ! #+fk#9"B"B"D"DK&55h6F6F6H6HII M()Kfk)K)KLLL&)===(2_5S 2 23	B2 2 2  
  &,,TD,III nnV44G 1$ 1T+t-D-D 1*/K1(+(=(=', !*$) /3u:: =#25I#I#I*4)>+?I+N)> )> )>+& +& %&
 !$		% 0 0 01 %*1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 $**3{/F/FyGXGXGZGZ/[/[+\+\]]]]?^ ^  ^  ^  ^  ^  ^  ^  ^  ^  ^  ^  ^  ^  ^  ^B    	MM($M7777 	 	 	D	 _--QTU]Q^Q^___s  /V! C$M00LA*K8	,L8K<<L?K< LM0LM0LAM0$V! 0M44V! 7M485V! -C(VT4&A*T	T4T!!T4$T!%T4(V4T88V;T8<AV	V! VV! VV! !
W,WW
WWWWc                    ddl }	 | j                            dd          }t          | j                            dd          pd          }|t          k    r#t          | ddt          dz  dz   d	id
          S t          | j        ||          \  }}|                    dd          }d|vrt          | ddid          S |d         \  }}|st          | ddid          S 	 t          |          }	n$# t          $ r t          | ddid          cY S w xY wt          |          }
|
                    dd           t          |||
          }t          | ddi|          S # t          $ r+}t          | dt          |          id          cY d}~S d}~wt          $ r= t!          d|                                z   d           t          | ddid          cY S w xY w)z%Handle archive upload and extraction.r   Nrk   r   rl   rm   rn   ro   rp   rq   rr   rS   rt   ru   rv   rw   rx   ry   TrU   okz[webui] upload extract error: r~   zArchive extraction failedr   )r   r   r%   r   r   r   r?   r&   r   r   rY   rZ   r   r   ri   r   r   r   )r   r   r'   r(   r.   r/   rS   rA   r   r   session_dirresultr   s                r>   handle_upload_extractr      s`   N**>2>>W_001A1EEJKK,,,Ww(`?OQU?UW[?[(`(`(`ajmnnnn'|^TTZZb11
Ww(BCCPPPP$V}* 	NWw(?@MMMM	JJ''AA 	J 	J 	JWw(;<SIIIIII	J-j99$666 X{CC400111 9 9 97CFF+C888888888 N N N.1A1AANNNN7$?@MMMMMMNsW   A2E! 9AE!   E! "C2 1E! 2DE! DAE! !
G+ FGAGGc                 V	   dd l }d }	 | j                            dd          }t          | j                            dd          pd          }|t          k    rZt          | ddt          dz  dz   did	
          |r5	 t          |                              d           S # t          $ r Y S w xY wS t          | j
        ||          \  }}d|vrKt          | ddid
          |r5	 t          |                              d           S # t          $ r Y S w xY wS |d         \  }}|sKt          | ddid
          |r5	 t          |                              d           S # t          $ r Y S w xY wS t          |          }	t          |	          j        pd}
t          j        d|
d          5 }|j        }|                    |           d d d            n# 1 swxY w Y   	 ddlm} n[# t&          $ rN t          | ddid
          cY |r5	 t          |                              d           S # t          $ r Y S w xY wS w xY w ||          }|                    d          st)          |                    d          pd          }d|                                v sd|                                v rdnd}t          | d|i|
          |r5	 t          |                              d           S # t          $ r Y S w xY wS t)          |                    d          pd                                          }t          | d|d          |r5	 t          |                              d           S # t          $ r Y S w xY wS # t.          $ rb}t          | dt)          |          id
          cY d }~|r5	 t          |                              d           S # t          $ r Y S w xY wS d }~wt          $ rt t1          d|                                z   d           t          | ddid 
          cY |r5	 t          |                              d           S # t          $ r Y S w xY wS w xY w# |r5	 t          |                              d           w # t          $ r Y w w xY ww xY w)!Nr   rk   r   rl   rm   rn   ro   rp   rq   rr   T)
missing_okrt   ru   rv   rw   z.webmz
webui-stt-F)prefixr^   delete)transcribe_audioz,Speech-to-text is unavailable on this serveri  successzTranscription failedunavailableznot configured
transcript)r   r   z[webui] transcribe error: r~   r   )r   r   r%   r   r   r   r   unlinkr   r?   r&   rI   r^   tempfileNamedTemporaryFiler=   r   tools.transcription_toolsr   ImportErrorri   r   r   r   r   r   )r   r   	temp_pathr'   r(   r.   r/   rA   r   rH   r^   tmpr   r   r9   rs   r   r   s                     r>   handle_transcriber     sh   I%**>2>>W_001A1EEJKK,,,Ww(`?OQU?UW[?[(`(`(`ajmnnn:  	Y&&$&7777   	9 (|^TTWw(BCCPPP4  	Y&&$&7777   	3  %V}* 	NWw(?@MMM.  	Y&&$&7777   	- *(33	i'27(VTYZZZ 	"^aIIIj!!!	" 	" 	" 	" 	" 	" 	" 	" 	" 	" 	" 	" 	" 	" 	"	eBBBBBBB 	e 	e 	eWw(VW`cddddd  	Y&&$&7777   		e!!),,zz)$$ 	=fjj))C-CDDC)SYY[[88<LPSPYPYP[P[<[<[SSadFWwnV<<<  	Y&&$&7777   	 L117R88>>@@
Z@@AA  	Y&&$&7777   	  9 9 97CFF+C88888888
  	Y&&$&7777   		  I I I*S^^-=-==TJJJJ7$:;CHHHHH 	Y&&$&7777   		I  	Y&&$&7777   	sS  A2N =#B!!
B.-B.20N %#D		
DD N =#E!!
E.-E.2<N .GN GN GN #G* )N *IN #H00
H=<H=IB
N #K33
L ?L AN #M33
N ?N 
Q, O+.Q,/Q/ 6#O
O'&O'+AQ,2Q/ 6#Q
Q'&Q'+Q,,Q/ /R(3#RR(
R$!R(#R$$R()!__doc__r   rM   r   r)   r   emailr   pathlibr   
api.configr   r   api.helpersr   r   
api.modelsr   api.workspacer	   r   tupler?   ri   rI   rR   rd   rY   r   bytesr   r   r    r@   r>   <module>r      s        				                2 2 2 2 2 2 2 2         " " " " " " ) ) ) ) ) ),, $E $ $ $ $NC C    
1$ 
1 
1 
1 
1C C D    & EI    dTk T    !B !B !BHl` l` l` l` l` l` l`^N N N<( ( ( ( (r@   