U
    he                     @   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<d/ Z d=d1 Z!d>d 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[<>"\']javascript: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parsedsuspicious_patternspattern r   8/var/www/html/JingleDetector/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$    

r0   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)r0   r   rstripospathbasenamer   r
   r"   r   r   r   validate_directory_pathg   s
    


r6   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: r1   <script|javascript:|data:|file:z%Suspicious content in configuration: [;&|`$]z%Potentially dangerous characters in: )

isinstancedictitemsr   matchr   r
   strr   r   )objr4   keyvalcheck_suspicious_contentr   r   rD      s    

z=validate_json_configuration.<locals>.check_suspicious_contentN)r7   )r;   r<   r   r
   r"   r   rC   r   validate_json_configuration}   s    

rE   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fieldrF   rG   r   r   r   validate_telegram_config   s    
rN   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passwordrH   rI   rJ   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.validatorsrS   )rK   rL   rM   rO   portrS   Zemail_validatorr   r   r   validate_email_config   s*    
rY   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methodrH   rI   rJ   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joinr;   r<   r=   r?   r   )rK   rL   rM   r   Zallowed_methodsra   header_nameheader_valuer   r   r   validate_webhook_config   s.    


rg   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
    !Template content cannot be empty.r9   z0Template contains potentially malicious content.r:   z3Template contains potentially dangerous characters.z\{\{([^}]+)\}\}r8   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    
rl   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
    "Confidence score must be a number.              ?-Confidence score must be between 0.0 and 1.0.Nr;   rT   floatr   r
   r"   r   r   r   validate_confidence_score6  s    
rs   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.rn   ro   z1Similarity threshold must be between 0.0 and 1.0.Nrq   r"   r   r   r   validate_similarity_thresholdG  s    
rt   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r;   rT   r   r
   r"   r   r   r   validate_positive_integerX  s    

rv   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
    rR   <   z2Segment duration must be between 1 and 60 seconds.Nrv   r   r
   r"   r   r   r   validate_segment_durationi  s    
ry   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
    rR   d   z+Maximum segments must be between 1 and 100.Nrx   r"   r   r   r   validate_max_segmentsy  s    
r{   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
    rR   
   z(Retry attempts must be between 1 and 10.Nrx   r"   r   r   r   validate_retry_attempts  s    
r}   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.Nrx   )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 r    bps.Nrx   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 r   r   Nrx   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)rv   r   r
   rd   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
    rR      z'Audio channels must be between 1 and 8.Nrx   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.ro   g      ^@z,Framerate must be between 1.0 and 120.0 fps.Nrq   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
    Slug cannot be empty.^[a-z0-9-]+$>Slug can only contain lowercase letters, numbers, and hyphens.-'Slug cannot start or end with a hyphen.--(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
    Name cannot be empty.z[<>]zName cannot contain HTML tags.[\x00-\x1f\x7f]z'Name cannot contain control characters.   rz   z/Name must be between 2 and 100 characters long.N)ri   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.rR   r|   z"Priority must be between 1 and 10.Nru   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.webprR   z.Image file must have one of these extensions: r`   N)r0   r3   r4   splitextr   r   r
   rd   )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   r7   z\s+ r   N)r;   r?   r   subri   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.r7   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 )
Nr1   r8   zInvalid context key:   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
   r;   r?   r/   r   r   r<   r=   list	enumeraterT   rr   booltype)rA   r   r4   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.)r7   )
r;   r<   r   r
   r=   jsondumpsr/   rV   rU   )contextrA   r   r   Zcontext_jsonr   r   r   validate_context_data  s    


r   c                 C   sx   | st tdtd| s(t tdt| dkr@t td| dsT| dr`t tdd| krtt td	d
S )z
    Validate slug format for URL-friendly identifiers.
    
    Args:
        value (str): Slug to validate
        
    Raises:
        ValidationError: If slug format is invalid
    r   r   r   rz   z&Slug is too long (max 100 characters).r   r   r   r   N)r   r
   r   r>   r/   r   r   r"   r   r   r   r     s    
c                 C   s   | st tdt| dkr(t tdtd| s@t td|  sTt tdddd	g}|D ] }t|| tjrbt td
qbdS )z
    Validate name format for human-readable names.
    
    Args:
        value (str): Name to validate
        
    Raises:
        ValidationError: If name format is invalid
    r   rz   z&Name is too long (max 100 characters).z^[a-zA-Z0-9\s\-_\.\(\)]+$z!Name contains invalid characters.zName cannot be only whitespace.z<[^>]*>r   r:   z,Name contains potentially malicious content.N)r   r
   r/   r   r>   ri   r   r   r   r   r   r   r   r   r     s    
c              	   C   sf   | dkrt tdzt| }W n$ ttfk
rD   t tdY nX |dk sV|dkrbt tddS )z
    Validate confidence score range (0.0 to 1.0).
    
    Args:
        value (float): Confidence score to validate
        
    Raises:
        ValidationError: If score is out of range
    Nz Confidence score cannot be None.rm   rn   ro   rp   )r   r
   rr   rV   rU   )r   scorer   r   r   rs     s    
c                 C   sr   | st tdt| dkr(t tdddddg}|D ] }t|| tjr8t tdq8|  snt td	d
S )z
    Validate template content for jingle detection.
    
    Args:
        value (str): Template content to validate
        
    Raises:
        ValidationError: If template content is invalid
    rh   r   z3Template content is too long (max 1000 characters).z<script[^>]*>r   r	   r:   z8Template content contains potentially malicious content.z+Template content cannot be only whitespace.N)r   r
   r/   r   r   r   ri   r   r   r   r   rl   4  s    
)'__doc__r   r3   urllib.parser   django.core.exceptionsr   rW   r   django.utils.translationr   r
   r   r0   r6   rE   rN   rY   rg   rl   rs   rt   rv   ry   r{   r}   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   <module>   sJ   2(#).!9%