U
    hIV                     @   s  d Z ddlZddlZddlZddlmZ ddlmZ ddl	m
Z dd Zdd	 Zd
d Zdd Zdd Zdd Zdd Zdd Zdd Zdd Zdd Zdd Zdd Zd d! Zd"d# Zd$d% Zd&d' Zd(d) Zd*d+ Zd,d- Zd.d/ Z d0d1 Z!d2d3 Z"d4d5 Z#d6d7 Z$d8d9 Z%d:d; Z&dS )<z?
Custom validators for enhanced input validation and security.
    N)ValidationError)URLValidator)gettext_lazyc                 C   s   t  }z||  W n  tk
r2   ttdY nX tj| }|jdkrVttd|jr|j dkrln|j	ds|j	dr| 
ds| 
dsttd	d
dddg}|D ] }t|| tjrttdqdS )z
    Validate HLS stream URL format and security.
    
    Args:
        value (str): URL to validate
        
    Raises:
        ValidationError: If URL is invalid or insecure
    zInvalid URL format.)httphttpsz*Only HTTP and HTTPS protocols are allowed.)	localhostz	127.0.0.1z0.0.0.0z192.168.z10.z.m3u8z.m3uz7URL must point to an HLS playlist file (.m3u8 or .m3u).z[<>"\']zjavascript:zdata:zfile:z+URL contains potentially malicious content.N)r   r   _urllibparseurlparseschemehostnamelower
startswithendswithresearch
IGNORECASE)valueurl_validatorparsedZsuspicious_patternspattern r   9/var/www/html/StreamProcessor/src/apps/core/validators.pyvalidate_hls_url   s,    
r   c              	      s    st tdd kr$t td dr^ddddd	g}t fd
d|D s^t tddddddddddg	}t fdd|D rt tdt dkrt tddS )z
    Validate file path for security and format.
    
    Args:
        value (str): File path to validate
        
    Raises:
        ValidationError: If path is invalid or insecure
    zFile path cannot be empty.z..z(Path traversal attempts are not allowed./z/tmp/z	/var/tmp/z/opt/streams/z/data/streams/z/app/media/c                 3   s   | ]}  |V  qd S N)r   ).0prefixr   r   r   	<genexpr>Z   s     z%validate_file_path.<locals>.<genexpr>z.Absolute paths must be in allowed directories.<>"'&|;`$c                 3   s   | ]}| kV  qd S r   r   )r   charr   r   r   r    _   s     z&File path contains invalid characters.i  z+File path is too long (max 500 characters).N)r   r   r   anylen)r   Zallowed_prefixesZsuspicious_charsr   r   r   validate_file_path?   s$    

r-   c                 C   s<   t |  | dr| d} dtj| kr8ttddS )z
    Validate directory path for security and format.
    
    Args:
        value (str): Directory path to validate
        
    Raises:
        ValidationError: If path is invalid or insecure
    r   .z+Path appears to be a file, not a directory.N)r-   r   rstripospathbasenamer   r   r   r   r   r   validate_directory_pathg   s
    


r3   c                    s0   t | tsttdd fdd	  |  dS )z
    Validate JSON configuration for notification channels.
    
    Args:
        value (dict): Configuration dictionary to validate
        
    Raises:
        ValidationError: If configuration is invalid
    z*Configuration must be a valid JSON object. c                    s   t | trP|  D ]:\}}td|s8ttd|  || d|  qnJt | trtd| tj	r|ttd| td| rttd| d S )N^[a-zA-Z_][a-zA-Z0-9_]*$zInvalid configuration key: r.   <script|javascript:|data:|file:z%Suspicious content in configuration: [;&|`$]z%Potentially dangerous characters in: )

isinstancedictitemsr   matchr   r   strr   r   )objr1   keyvalcheck_suspicious_contentr   r   rA      s    

z=validate_json_configuration.<locals>.check_suspicious_contentN)r4   )r8   r9   r   r   r   r   r@   r   validate_json_configuration}   s    

rB   c                 C   s   ddg}|D ]:}|| kr*t td| | | st td| dq| d }td|sht tdt| d }td|st td	d
S )z
    Validate Telegram notification configuration.
    
    Args:
        config (dict): Telegram configuration
        
    Raises:
        ValidationError: If configuration is invalid
    	bot_tokenchat_idMissing required field: Field  cannot be emptyz^\d+:[A-Za-z0-9_-]+$z"Invalid Telegram bot token format.z^-?\d+$z Invalid Telegram chat ID format.N)r   r   r   r;   r<   )configrequired_fieldsfieldrC   rD   r   r   r   validate_telegram_config   s    
rK   c              	   C   s  ddddg}|D ]:}|| kr.t td| | | st td| dq| d }td|slt td	z2t| d }d
|  krdksn t tdW n$ ttfk
r   t tdY nX ddlm} | }z|| d  W n" t k
r   t tdY nX dS )z
    Validate email notification configuration.
    
    Args:
        config (dict): Email configuration
        
    Raises:
        ValidationError: If configuration is invalid
    	smtp_hostZ	smtp_portusernamepasswordrE   rF   rG   z^[a-zA-Z0-9.-]+$zInvalid SMTP host format.   i  z&SMTP port must be between 1 and 65535.z"SMTP port must be a valid integer.r   )EmailValidatorzInvalid email address format.N)	r   r   r   r;   int
ValueError	TypeErrordjango.core.validatorsrP   )rH   rI   rJ   rL   portrP   Zemail_validatorr   r   r   validate_email_config   s*    
rV   c                 C   s6  ddg}|D ]:}|| kr*t td| | | st td| dqt }z|| d  W n  t k
r~   t tdY nX ddd	d
g}| d  |krt tdd| d| kr2| d }t|tst td| D ]L\}}t|trt|tst td|	 dkrt td| dqdS )z
    Validate webhook notification configuration.
    
    Args:
        config (dict): Webhook configuration
        
    Raises:
        ValidationError: If configuration is invalid
    urlmethodrE   rF   rG   zInvalid webhook URL format.GETPOSTPUTPATCHzHTTP method must be one of: , headersz$Headers must be a valid JSON object.z(Header names and values must be strings.)hostzcontent-lengthzHeader z is not allowed.N)
r   r   r   upperjoinr8   r9   r:   r<   r   )rH   rI   rJ   r   Zallowed_methodsr^   header_nameheader_valuer   r   r   validate_webhook_config   s.    


rd   c                 C   s   | r|   sttdtd| tjr4ttdtd| rLttdtd| }|D ]*}|  }td|s\ttd| q\t| d	krttd
dS )z
    Validate notification template content for security.
    
    Args:
        value (str): Template content to validate
        
    Raises:
        ValidationError: If template contains unsafe content
    z!Template content cannot be empty.r6   z0Template contains potentially malicious content.r7   z3Template contains potentially dangerous characters.z\{\{([^}]+)\}\}r5   zInvalid template variable: i  z3Template content is too long (max 5000 characters).N)	stripr   r   r   r   r   findallr;   r,   )r   Ztemplate_varsvarr   r   r   validate_template_content  s    
rh   c                 C   s@   t | ttfsttdd|   kr.dks<n ttddS )z
    Validate confidence score range.
    
    Args:
        value (float): Confidence score to validate
        
    Raises:
        ValidationError: If score is out of valid range
    z"Confidence score must be a number.              ?z-Confidence score must be between 0.0 and 1.0.Nr8   rQ   floatr   r   r   r   r   r   validate_confidence_score6  s    
rm   c                 C   s@   t | ttfsttdd|   kr.dks<n ttddS )z
    Validate similarity threshold range.
    
    Args:
        value (float): Similarity threshold to validate
        
    Raises:
        ValidationError: If threshold is out of valid range
    z&Similarity threshold must be a number.ri   rj   z1Similarity threshold must be between 0.0 and 1.0.Nrk   r   r   r   r   validate_similarity_thresholdG  s    
rn   c                 C   s.   t | tsttd| dkr*ttddS )z
    Validate positive integer values.
    
    Args:
        value (int): Integer to validate
        
    Raises:
        ValidationError: If value is not a positive integer
    zValue must be an integer.r   z!Value must be a positive integer.Nr8   rQ   r   r   r   r   r   r   validate_positive_integerX  s    

rp   c                 C   s.   t |  d|   krdks*n ttddS )z
    Validate HLS segment duration.
    
    Args:
        value (int): Segment duration in seconds
        
    Raises:
        ValidationError: If duration is invalid
    rO   <   z2Segment duration must be between 1 and 60 seconds.Nrp   r   r   r   r   r   r   validate_segment_durationi  s    
rs   c                 C   s.   t |  d|   krdks*n ttddS )z
    Validate maximum segments count.
    
    Args:
        value (int): Maximum segments count
        
    Raises:
        ValidationError: If count is invalid
    rO   d   z+Maximum segments must be between 1 and 100.Nrr   r   r   r   r   validate_max_segmentsy  s    
ru   c                 C   s.   t |  d|   krdks*n ttddS )z
    Validate retry attempts count.
    
    Args:
        value (int): Retry attempts count
        
    Raises:
        ValidationError: If count is invalid
    rO   
   z(Retry attempts must be between 1 and 10.Nrr   r   r   r   r   validate_retry_attempts  s    
rw   c                 C   s   t |  t | d\}}d\}}||   kr4|ksPn ttd| d| d||  krd|ksn ttd| d| d| | }d|  krdksn ttd	d
S )z
    Validate video dimensions.
    
    Args:
        width (int): Video width
        height (int): Video height
        
    Raises:
        ValidationError: If dimensions are invalid
    )i@  i   )   i  zVideo width must be between  and z pixels.zVideo height must be between g      ?g      @z/Video aspect ratio must be between 0.5 and 4.0.Nrr   )widthheightZ	min_width	max_widthZ
min_heightZ
max_heightaspect_ratior   r   r   validate_video_dimensions  s    r~   c                 C   sD   t |  d}d}||   kr$|ks@n ttd| d| ddS )z
    Validate video bitrate.
    
    Args:
        value (int): Video bitrate in bps
        
    Raises:
        ValidationError: If bitrate is invalid
    i izVideo bitrate must be between ry    bps.Nrr   r   min_bitratemax_bitrater   r   r   validate_video_bitrate  s
    
r   c                 C   sD   t |  d}d}||   kr$|ks@n ttd| d| ddS )z
    Validate audio bitrate.
    
    Args:
        value (int): Audio bitrate in bps
        
    Raises:
        ValidationError: If bitrate is invalid
    i }  i  zAudio bitrate must be between ry   r   Nrr   r   r   r   r   validate_audio_bitrate  s
    
r   c                 C   sH   t |  ddddddddg}| |krDttd	d
tt| ddS )z
    Validate audio sample rate.
    
    Args:
        value (int): Sample rate in Hz
        
    Raises:
        ValidationError: If sample rate is invalid
    i@  i+  i>  i"V  iD  i  i w i  zSample rate must be one of: r]   z Hz.N)rp   r   r   ra   mapr<   )r   Zvalid_ratesr   r   r   validate_sample_rate  s    
r   c                 C   s.   t |  d|   krdks*n ttddS )z
    Validate audio channel count.
    
    Args:
        value (int): Number of audio channels
        
    Raises:
        ValidationError: If channel count is invalid
    rO      z'Audio channels must be between 1 and 8.Nrr   r   r   r   r   validate_audio_channels  s    
r   c                 C   s@   t | ttfsttdd|   kr.dks<n ttddS )z
    Validate video framerate.
    
    Args:
        value (float): Framerate in fps
        
    Raises:
        ValidationError: If framerate is invalid
    zFramerate must be a number.rj   g      ^@z,Framerate must be between 1.0 and 120.0 fps.Nrk   r   r   r   r   validate_framerate  s    
r   c                 C   s   | st tdtd| s(t td| ds<| drHt tdd| kr\t tddt|   krtd	ksn t td
dS )z
    Validate slug format for URL safety.
    
    Args:
        value (str): Slug to validate
        
    Raises:
        ValidationError: If slug format is invalid
    zSlug cannot be empty.z^[a-z0-9-]+$z>Slug can only contain lowercase letters, numbers, and hyphens.-z'Slug cannot start or end with a hyphen.z--z(Slug cannot contain consecutive hyphens.   2   z.Slug must be between 3 and 50 characters long.N)r   r   r   r;   r   r   r,   r   r   r   r   validate_slug_format  s    
r   c                 C   sz   | r|   sttd|   } td| r8ttdtd| rPttddt|   krhdksvn ttdd	S )
z
    Validate name format for display purposes.
    
    Args:
        value (str): Name to validate
        
    Raises:
        ValidationError: If name format is invalid
    zName cannot be empty.z[<>]zName cannot contain HTML tags.[\x00-\x1f\x7f]z'Name cannot contain control characters.   rt   z/Name must be between 2 and 100 characters long.N)re   r   r   r   r   r,   r   r   r   r   validate_name_format1  s    
r   c                 C   s<   t | tsttdd|   kr*dks8n ttddS )z
    Validate priority value.
    
    Args:
        value (int): Priority value
        
    Raises:
        ValidationError: If priority is invalid
    zPriority must be an integer.rO   rv   z"Priority must be between 1 and 10.Nro   r   r   r   r   validate_priorityM  s    

r   c                 C   sR   | st tdtd| s(t tddt|   kr@dksNn t tddS )z
    Validate event type format.
    
    Args:
        value (str): Event type to validate
        
    Raises:
        ValidationError: If event type is invalid
    zEvent type cannot be empty.z^[a-z][a-z0-9_]*$zREvent type must be in snake_case format (lowercase letters, numbers, underscores).r   r   z4Event type must be between 3 and 50 characters long.N)r   r   r   r;   r,   r   r   r   r   validate_event_type^  s    
r   c                 C   sP   t |  ddddddg}tj| d  }||krLttdd	| d
S )z
    Validate image file path and format.
    
    Args:
        value (str): Image file path to validate
        
    Raises:
        ValidationError: If path or format is invalid
    z.jpgz.jpegz.pngz.bmpz.tiffz.webprO   z.Image file must have one of these extensions: r]   N)r-   r0   r1   splitextr   r   r   ra   )r   Zvalid_extensionsfile_extr   r   r   validate_image_file_patht  s
    
r   c                 C   sD   t | ts| S tdd| } tdd|  } ddl}|| } | S )z
    Sanitize user input for safe storage and display.
    
    Args:
        value (str): Input to sanitize
        
    Returns:
        str: Sanitized input
    r   r4   z\s+ r   N)r8   r<   r   subre   htmlescape)r   r   r   r   r   sanitize_user_input  s    


r   c              	      s   t | tsttdd
 fdd	 |  D ]\}} || q,ddl}z&|| }t|dkrlttdW n$ tt	fk
r   ttd	Y nX dS )z
    Validate context data for templates and notifications.
    
    Args:
        context (dict): Context data to validate
        
    Raises:
        ValidationError: If context data is invalid
    zContext must be a dictionary.r4   c                    s  |r| d|  n| }t d| s4ttd|  t|trt|dkr\ttd| t d|t jr~ttd| nt|t	r|
 D ]\}} ||| qnht|trt|D ](\}}t|tt	fr d| || qn*t|ttttd fsttd	| d S )
Nr.   r5   zInvalid context key: i  zContext value too long: z<script|javascript:|data:zSuspicious content in context: Zitem_zInvalid context value type: )r   r;   r   r   r8   r<   r,   r   r   r9   r:   list	enumeraterQ   rl   booltype)r>   r   r1   current_pathZ
nested_keynested_valueiitemvalidate_context_valuer   r   r     s"    


z5validate_context_data.<locals>.validate_context_valuer   Ni'  z%Context data is too large (max 10KB).z'Context data must be JSON serializable.)r4   )
r8   r9   r   r   r:   jsondumpsr,   rS   rR   )contextr>   r   r   Zcontext_jsonr   r   r   validate_context_data  s    


r   )'__doc__r   r0   urllib.parser	   django.core.exceptionsr   rT   r   django.utils.translationr   r   r   r-   r3   rB   rK   rV   rd   rh   rm   rn   rp   rs   ru   rw   r~   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   <module>   sB   2(#).!