o
    <h:c                     @   s   d Z ddlZddlm  mZ ddlZddlZddl	Z	ddl
Z
ddlmZmZmZmZmZmZmZmZmZ ejjdd Zejjdd Zejjdd	 Zejjd
d Zejjdd Zejjdd Zejjdd Zejjdd Zejjdd ZdS )a  
test_security_enhancements.py

Purpose:
  Unit tests for the security enhancement functions that implement protection against
  sophisticated attack vectors. These tests validate that security functions work
  correctly under normal conditions and properly block malicious inputs while
  maintaining usability for legitimate users.

Test Coverage:
  - Timing attack protection validation
  - Geographic coordinate validation with bounds checking
  - Error message sanitization to prevent information disclosure
  - Filename security validation including path traversal prevention
  - Cryptographic token generation and verification
  - API input validation with security pattern detection
  - Security headers middleware functionality

Security Testing Philosophy:
  Each test validates both positive cases (legitimate inputs work correctly) and
  negative cases (malicious inputs are properly blocked). Tests ensure security
  measures are transparent to legitimate users while effectively blocking attacks.
    N)	secure_password_checkvalidate_geographic_coordinatessanitize_error_messagevalidate_filename_securitygenerate_secure_tokenverify_hmac_token#rate_limit_with_exponential_backoffvalidate_api_inputsecurity_headers_middlewarec                  C   s  ddl } d}| |d|  d}d|d}td||}d}||u }|s\td|fd	||fd
t	 v s<t
|rAt|nd
t|d }tdd d|i }tt|d }}tdd|}d}||u }|std|fd	||fd
t	 v st
|rt|nd
t|d }tdd d|i }tt|d }}td|d}d}||u }|std|fd	||fd
t	 v st
|rt|nd
t|d }tdd d|i }tt|d }}g }	g }
tdD ]}t }tdd| t }|	||  qtdD ]}t }tddd t }|
||  qt|	t|	 }t|
t|
 }t|| }d}||k }|std|fd||fdt	 v sat
|rft|ndt|d }td|ddd d|i }tt|d }}dS )z
    Test that password checking maintains consistent timing regardless of username validity.
    
    This prevents timing-based username enumeration attacks by ensuring bcrypt
    operations run in both valid and invalid username scenarios.
    r   Ntestpassword123utf-8testuser)usernamepassword_hashTisz%(py0)s is %(py3)sresultpy0py3z/Valid password should authenticate successfully
>assert %(py5)spy5wrongpasswordFz+Invalid password should fail authenticationnonexistentz,Non-existent user should fail authentication
   g?)<)z%(py0)s < %(py3)stiming_diffzTiming difference too large: z.4fz0s - potential username enumeration vulnerability)bcrypthashpwencodegensaltdecoder   
@pytest_ar_call_reprcompare@py_builtinslocals_should_repr_global_name	_saferepr_format_assertmsgAssertionError_format_explanationrangetimeperf_counterappendsumlenabs)r   passwordr   valid_user_rowr   @py_assert2@py_assert1@py_format4@py_format6valid_timesinvalid_times_startend	valid_avginvalid_avgr    r@   :/var/www/html/tests/security/test_security_enhancements.py-test_secure_password_check_timing_consistency*   s8   rB   c                  C   s
  t dd\} }}d}| |u }|sEtd|fd| |fdt v s%t| r*t| ndt|d }tdd	 d
|i }tt	|d }}d}||u }|std|fd||fdt v sft|rkt|ndt|d }tdd	 d
|i }tt	|d }}d}||k}|std|fd||fdt v st|rt|ndt|d }tdd	 d
|i }tt	|d }}g d}|D ]\}}	t ||	\} }}d}| |u }|s#td|fd| |fdt v st| rt| ndt|d }td| d|	 dd	 d
|i }tt	|d }}||	f}||k}|sitd|fd||fdt v sIt|rNt|ndt|d }tdd	 d
|i }tt	|d }}qg d}
|
D ]\}}	t ||	\} }}d}| |u }|std|fd| |fdt v st| rt| ndt|d }td| dd	 d
|i }tt	|d }}d}|j
}| }||v }|std|fd||ft|dt v st|rt|ndt|t|d }td | d! d"|i }tt	|d } } }}d}||u }|satd|fd||fdt v sAt|rFt|ndt|d }td#d	 d
|i }tt	|d }}qtg d$}|D ]\}}	t ||	\} }}d}| |u }|std|fd| |fdt v st| rt| ndt|d }td%|	 dd	 d
|i }tt	|d }}d&}|j
}| }||v }|std|fd||ft|dt v st|rt|ndt|t|d }td'|	 d! d"|i }tt	|d } } }}d}||u }|sZtd|fd||fdt v s:t|r?t|ndt|d }td#d	 d
|i }tt	|d }}qmg d(}|D ]\}}	t ||	\} }}d}| |u }|std|fd| |fdt v st| rt| ndt|d }td)| d|	 d*d	 d
|i }tt	|d }}|d+ }t|t}|std,d- d.t v sttrttnd.t|d/t v sttrttnd/t|d0 }tt	|d }}|d1 }t|t}|sWtd2d- d.t v s+ttr0ttnd.t|d/t v sBttrGttnd/t|d0 }tt	|d }}qfd3d4d5d6d7d8td9d:fd;td9ftd<d:fd;td<fg
}|D ]\}}	t ||	\} }}d}| |u }|std|fd| |fdt v st| rt| ndt|d }td=| d|	 d>d	 d
|i }tt	|d }}d}||u}|std?|fd@||fdt v st|rt|ndt|d }tdAd	 d
|i }tt	|d }}d}||u }|sVtd|fd||fdt v s6t|r;t|ndt|d }tdBd	 d
|i }tt	|d }}q{dS )CzBTest geographic coordinate validation with proper bounds checking.v^F@]P/@Tr   r   successr   z(Valid coordinates should pass validationr   r   Nerrorz/Valid coordinates should not have error message)rC   rD   ==)z%(py0)s == %(py3)scoordsz.Valid coordinates should be returned unchanged))g     V@     f@)g     V     f)        rL   )     F@g      /@zBoundary coordinates (, z) should be validz1Boundary coordinates should be returned unchanged))g     V@      .@)g     VrO   )rJ   rO   )rK   rO   FzInvalid latitude z should be rejectedu   geografska širinainzD%(py1)s in %(py7)s
{%(py7)s = %(py5)s
{%(py5)s = %(py3)s.lower
}()
}py1r   r   py7z'Should have latitude error message for 
>assert %(py9)spy9z&Invalid coordinates should return None))rM   g     f@)rM   g     f)rM   g     v@)rM   g     vzInvalid longitude u   geografska dužinaz(Should have longitude error message for ))z	45.815399z	15.981919)4515)45.015.0zString coordinates (z) should convert and validater   z"Converted latitude should be float7
>assert %(py5)s
{%(py5)s = %(py0)s(%(py2)s, %(py3)s)
}
isinstancefloatr   py2r   r      z#Converted longitude should be float)invalidr[   )rZ   rb   )Nr[   )rZ   N)z'; DROP TABLE coords; --r[   )z<script>alert('xss')</script>r[   infrO   rM   nanzInvalid input (z) should be rejectedis notz%(py0)s is not %(py3)sz'Invalid input should have error messagez,Invalid input should return None coordinates)r   r#   r$   r%   r&   r'   r(   r)   r*   r+   lowerr]   r^   )rE   rF   rI   r5   r6   r7   r8   boundary_testslatlnginvalid_lat_tests@py_assert0@py_assert4@py_assert6@py_format8@py_format10invalid_lng_testsstring_coordinate_testsinvalid_inputsr@   r@   rA   $test_validate_geographic_coordinatesd   sX   



ru   c                  C   s  t dt dt dt dg} | D ]}t|d}d}|j}| }||v}|sftd|fd||ft|d	t v s?t|rDt|nd	t|t|d
 }t	d| d d|i }t
t|d } } }}d}|j}| }||v}|std|fd||ft|d	t v st|rt|nd	t|t|d
 }t	d| d d|i }t
t|d } } }}d}|j}| }||v}|std|fd||ft|d	t v st|rt|nd	t|t|d
 }t	d| d d|i }t
t|d } } }}d}|j}| }||v}|sltd|fd||ft|d	t v sEt|rJt|nd	t|t|d
 }t	d| d d|i }t
t|d } } }}d}|j}| }||v }|std|fd||ft|d	t v st|rt|nd	t|t|d
 }t	dd d|i }t
t|d } } }}qt dt dt dt dg}	|	D ]E}t|d}d}||v}|s&td|fd||ft|d	t v st|rt|nd	d }
t	d| d d |
i }t
t|d }}d!}|j}| }||v}|s{td|fd||ft|d	t v sTt|rYt|nd	t|t|d
 }t	d| d d|i }t
t|d } } }}d"}||v}|std|fd||ft|d	t v st|rt|nd	d }
t	d| d d |
i }t
t|d }}d#}|j}| }||v }|std|fd||ft|d	t v st|rt|nd	t|t|d
 }t	d$d d|i }t
t|d } } }}qt d%t d&t d'g}|D ]}t|d(}d)}||v}|sytd|fd||ft|d	t v sZt|r_t|nd	d }
t	d*| d d |
i }t
t|d }}d+}||v}|std|fd||ft|d	t v st|rt|nd	d }
t	d,| d d |
i }t
t|d }}d-}|j}| }||v }|std|fd||ft|d	t v st|rt|nd	t|t|d
 }t	d.d d|i }t
t|d } } }}q/t d/}t|d0}d1}|j}| }||v }|sstd|fd||ft|d	t v sOt|rTt|nd	t|t|d
 }t	d2d d|i }t
t|d } } }}dS )3zBTest error message sanitization to prevent information disclosure.z(UNIQUE constraint failed: users.usernamezBsqlite3.OperationalError: table users has no column named passwordz Database disk image is malformedzFOREIGN KEY constraint faileddatabasesqlitenot in)zH%(py1)s not in %(py7)s
{%(py7)s = %(py5)s
{%(py5)s = %(py3)s.lower
}()
}	sanitizedrS   zDatabase error leaked info: rV   rW   Ntablecolumn
constraintu   greška pri obradi podatakarP   rR   z*Should have generic database error messagezPermission denied: /etc/passwdz.No such file or directory: /var/www/secret.txtz.Access is denied to C:\Windows\System32\configz&File not found: /home/user/.ssh/id_rsa
filesystemz/etc/)z%(py1)s not in %(py3)s)rT   r   zFile path leaked: r   r   zc:\z.sshu   greška pri pristupu datoteciz&Should have generic file error messagez*Connection timeout to internal-server:3306z"Network unreachable: 192.168.1.100zSocket connection failednetworkz192.168zIP address leaked: z:3306zPort number leaked: u   greška mrežez)Should have generic network error messagezSome random error messagegenericu   došlo je do greškez!Should have generic error message)	Exceptionr   rh   r#   r$   r(   r%   r&   r'   r)   r*   r+   )database_errorsrF   rz   rm   rn   ro   r5   rp   rq   filesystem_errorsr7   r8   network_errorsgeneric_errorr@   r@   rA   test_sanitize_error_message   sF   





r   c                  C   s	  g d} | D ]}t |\}}d}||u }|sNtd|fd||fdt v s+t|r0t|ndt|d }td| d d	|i }tt	|d
 }}d
}||u }|std|fd||fdt v sot|rtt|ndt|d }td| d d	|i }tt	|d
 }}qg d}|D ]}t |\}}d}||u }|std|fd||fdt v st|rt|ndt|d }td| d d	|i }tt	|d
 }}d
}||u}|s,td|fd||fdt v s	t|rt|ndt|d }td| d d	|i }tt	|d
 }}d}	|j
}
|
 }|	|v }|std|fd|	|ft|	dt v sZt|r_t|ndt|
t|d }td| d d|i }tt	|d
 }	 } }
}qg d}|D ]}t |\}}d}||u }|std|fd||fdt v st|rt|ndt|d }td| d d	|i }tt	|d
 }}d
}||u}|s"td|fd||fdt v st|rt|ndt|d }td| d d	|i }tt	|d
 }}d}	|j
}
|
 }|	|v }|swtd|fd|	|ft|	dt v sPt|rUt|ndt|
t|d }td| d d|i }tt	|d
 }	 } }
}qg d}|D ]}t |\}}d}||u }|std|fd||fdt v st|rt|ndt|d }td | d d	|i }tt	|d
 }}d
}||u}|std|fd||fdt v st|rt|ndt|d }td!| d d	|i }tt	|d
 }}qd"}t |\}}d}||u }|sgtd|fd||fdt v sGt|rLt|ndt|d }td#d d	|i }tt	|d
 }}d$}	|j
}
|
 }|	|v }|std|fd|	|ft|	dt v st|rt|ndt|
t|d }td%d d|i }tt	|d
 }	 } }
}d&}t |\}}d}||u }|s	td|fd||fdt v st|rt|ndt|d }td'd d	|i }tt	|d
 }}d
}||u}|sMtd|fd||fdt v s-t|r2t|ndt|d }td(d d	|i }tt	|d
 }}t d)\}}d}||u }|std|fd||fdt v swt|r|t|ndt|d }td*d d	|i }tt	|d
 }}t d
\}}d}||u }|std|fd||fdt v st|rt|ndt|d }td+d d	|i }tt	|d
 }}d
S ),zFTest filename validation for security issues including path traversal.)z	image.jpgzcamera_photo_123.pngz%PICT_20231201_120000_123456789012.jpgztest_file.jpegzdocument.pdfTr   r   is_validr   zValid filename should pass: r   r   NrF   z&Valid filename should not have error: )z../../../etc/passwdz$..\..\..\windows\system32\config\samz....//....//....//etc/passwdzfile/../../../sensitive.txtz..%2f..%2f..%2fetc%2fpasswdFz"Path traversal should be blocked: re   rg   z*Path traversal should have error message: zneispravno ime datotekerP   rR   rS   z'Should have generic error message for: rV   rW   )	zmalicious.phpzscript.php3zbackdoor.aspz	shell.jspz
trojan.exez	virus.batzconfig.htaccesszsecrets.iniz
exploit.pyz'Dangerous extension should be blocked: z'Dangerous extension should have error: znedozvoljena vrsta datotekez!Should have file type error for: )zfile<script>.jpgzfile>redirect.jpgzfile|pipe.jpgzfile:stream.jpgzfile*wildcard.jpgzfile?query.jpgzfile"quote.jpgz&Special characters should be blocked: z&Special characters should have error: a0  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.jpgz'Overly long filename should be rejectedu   predugačkoz Should have length error messagez	file .jpgz%Null byte injection should be blockedz-Null byte injection should have error message z!Empty filename should be rejectedz None filename should be rejected)r   r#   r$   r%   r&   r'   r(   r)   r*   r+   rh   )valid_filenamesfilenamer   rF   r5   r6   r7   r8   path_traversal_filenamesrm   rn   ro   rp   rq   dangerous_filenamesspecial_char_filenameslong_filenamenull_byte_filenamer@   r@   rA   test_validate_filename_security   sD   
r   c               	   C   sJ  dd t dD } t| }t|}d}||k}|sxtd|fd||fdt v s.ttr3ttnddt v s?ttrDttnddt v sPt| rUt| ndt|t|t|d	 }t	d
d d|i }t
t|d } } }}| dd D ]}t|}d}||k}	|	std|	fd||fdt v sttrttnddt v st|rt|ndt|t|d }
t	dt| dd d|
i }t
t|d } }	}t|}d}||k}	|	sKtd|	fd||fdt v sttrttnddt v s!t|r&t|ndt|t|d }
t	dt| dd d|
i }t
t|d } }	}qtd}td}t|}d}||k}	|	std|	fd||fdt v s~ttrttnddt v st|rt|ndt|t|d }
t	d d d|
i }t
t|d } }	}t|}d!}||k}	|	std|	fd||fdt v sttrttndd"t v st|rt|nd"t|t|d }
t	d#d d|
i }t
t|d } }	}d$dl}t|j|j d% }| dd D ]r}t|d&}|| }t|}d$}||k}	|	std|	fd'||fdt v sattrfttndd(t v stt|ryt|nd(t|t|d }
t	d)| d d|
i }t
t|d } }	}q0dS )*z8Test secure token generation for cryptographic strength.c                 S   s   g | ]}t  qS r@   )r   ).0r;   r@   r@   rA   
<listcomp>L  s    z.test_generate_secure_token.<locals>.<listcomp>d   rG   )zN%(py6)s
{%(py6)s = %(py0)s(%(py4)s
{%(py4)s = %(py1)s(%(py2)s)
})
} == %(py9)sr1   settokens)r   rT   r`   py4py6rW   z%All generated tokens should be uniquez
>assert %(py11)spy11Nr   (   >=)z0%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} >= %(py6)stoken)r   rT   r   r   zToken too short: z chars
>assert %(py8)spy82   <=)z0%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} <= %(py6)szToken too long:    @      short_tokenz&Short token should be encoded properlyP   
long_tokenz%Long token should be encoded properlyr   z-_=)z0%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} == %(py6)sinvalid_charsz#Token contains invalid characters: )r,   r   r1   r#   r$   r%   r&   r'   r(   r)   r*   r+   r   stringascii_lettersdigitsrstrip)r   @py_assert3@py_assert5@py_assert8@py_assert7rq   @py_format12r   r5   rn   @py_format7@py_format9r   r   r   valid_charstoken_charsr   r@   r@   rA   test_generate_secure_tokenG  s    r   c               	   C   st  d} d}t | d|dtj }t||| }d}||u }|sWtd|fd||fdt	
 v s7t|r<t|ndt|d }td	d
 d|i }tt|d }}d}t||| }d}||u }|std|fd||fdt	
 v st|rt|ndt|d }tdd
 d|i }tt|d }}d}	t|	|| }d}||u }|std|fd||fdt	
 v st|rt|ndt|d }tdd
 d|i }tt|d }}d}
t|||
}d}||u }|s5td|fd||fdt	
 v st|rt|ndt|d }tdd
 d|i }tt|d }}d|| f|d| f||dfd|| f|d| fg}|D ]f\}}}zVt|||}d}||u }|std|fd||fdt	
 v s}t|rt|ndt|d }td| d| d| d
 d|i }tt|d }}W qQ ty   Y qQw dS )z<Test HMAC token verification for integrity and authenticity.test_secret_key_12345user_data_to_signr   Tr   r   r   r   z+Valid HMAC token should verify successfullyr   r   Ninvalid_token_12345Fz+Invalid HMAC token should fail verificationmodified_user_dataz+Modified data should fail HMAC verificationwrong_secret_keyz)Wrong secret key should fail verificationr   zMalformed input should fail: rN   )hmacnewr    hashlibsha256	hexdigestr   r#   r$   r%   r&   r'   r(   r)   r*   r+   r   )
secret_keydatavalid_tokenr   r5   r6   r7   r8   invalid_tokenmodified_datawrong_secretmalformed_tests	test_data
test_tokentest_secretr@   r@   rA   test_verify_hmac_tokeng  sD   r   c                  C   s  dd t ddD } t dt| D ]L}| | }| |d  }||k}|sWtd|fd||ft|t|d }td| |d   d	| |  d
 d|i }tt|d } }}q| d }d}||k}|std|fd||ft|t|d }td| d  d
 d|i }tt|d } }}d}t|}d}||k}	|	std|	fd||fdt	
 v sttrttndt|t|t|d }
tdd d|
i }tt|d } } }	}d}| }t|}d}||k}|sAtd|fd||fdt	
 v sttrttndt|t|t|d }tdd d|i }tt|d } } } }}td}d}||k}|std|fd ||fd!t	
 v sot|rtt|nd!t|d" }td#| d$ d%|i }tt|d }}td}td&}td'}d&}|| }	||	k}|std|fd(||	fd)t	
 v st|rt|nd)d*t	
 v st|rt|nd*t|d+ }td,| d	| d- d.|i }
tt|
d } }}	d/}|| }	||	k}|sbtd|fd(||	fd0t	
 v s)t|r.t|nd0d*t	
 v s<t|rAt|nd*t|d+ }td1| d	| d- d.|i }
tt|
d } }}	dS )2z7Test exponential backoff calculation for rate limiting.c                 S   s   g | ]}t |qS r@   )r   )r   ir@   r@   rA   r     s    z<test_rate_limit_with_exponential_backoff.<locals>.<listcomp>ra      r   )z%(py1)s >= %(py4)srT   r   zDelay should increase: z -> 
>assert %(py6)sr   Nr      rG   z%(py1)s == %(py4)sz.First attempt should have 5 second delay, got )z0%(py4)s
{%(py4)s = %(py0)s(%(py2)s)
} == %(py7)sr   )r   r`   r   rU   z$Zero attempts should have zero delayrV   rW   )z1%(py5)s
{%(py5)s = %(py0)s(-%(py2)s)
} == %(py8)s)r   r`   r   r   z(Negative attempts should have zero delayz
>assert %(py10)spy10r   i  r   )z%(py0)s <= %(py3)s
high_delayr   z&Delay should be capped at 1 hour, got r   r         )z%(py0)s == (%(py2)s * %(py4)s)delay2delay1r   r`   r   zDelay should double: 
>assert %(py7)srU      delay3zDelay should quadruple: )r,   r1   r#   r$   r(   r)   r*   r+   r   r%   r&   r'   )delaysr   rm   r   r5   @py_format5r   r6   ro   r   rp   rq   rn   r   r   @py_format11r   r7   r8   r   r   r   r@   r@   rA   (test_rate_limit_with_exponential_backoff  s   ~r   c                  C   s
  t ddddt ddddt ddddd} d	d
dd}t|| \}}}d}||u }|s`td|fd||fdt v s@t|rEt|ndt|d }tdd d|i }t	t
|d }}d}||u }|std|fd||fdt v st|rt|ndt|d }tdd d|i }t	t
|d }}||k}|std|fd||fdt v st|rt|nddt v st|rt|ndd }	tdd d|	i }
t	t
|
d}dd	i}t|| \}}}d}||u }|s;td|fd||fdt v st|r t|ndt|d }td d d|i }t	t
|d }}d}||u}|std!|fd"||fdt v s_t|rdt|ndt|d }td#d d|i }t	t
|d }}d$}|j}| }||v }|std%|fd&||ft|dt v st|rt|ndt|t|d' }td(d) d*|i }t	t
|d } } }}d+d
d,dd-fd.d
d,dd/fd0d1d,dd-fd0d2d,dd/fg}|D ]\}}t|| \}}}d}||u }|sHtd|fd||fdt v s%t|r*t|ndt|d }td3| d d|i }t	t
|d }}|j}| }||v }|std%|fd4||fd5t v spt|rut|nd5dt v st|rt|ndt|t|d6 }td7| d8 d9|i }t	t
|d } }}qd0d
d:dd0d
d;dd0d
d<dd0d
d=dd0d
d>dg}|D ]}t|| \}}}d}||u }|std|fd||fdt v st|rt|ndt|d }td?| d d|i }t	t
|d }}d}||u}|sctd!|fd"||fdt v s@t|rEt|ndt|d }td@| d d|i }t	t
|d }}dA}|j}| }||v }|std%|fd&||ft|dt v st|rt|ndt|t|d' }tdB| d) d*|i }t	t
|d } } }}qd	dCdd}t|| \}}}d}||u }|std|fd||fdt v st|rt|ndt|d }tdDd d|i }t	t
|d }}|dE }t|t }|s_tdFdG dHt v s3ttr8ttndHt|dIt v sJtt rOtt ndIt|dJ }t	t
|d }}dK}t|| \}}}d}||u }|std|fd||fdt v st|rt|ndt|d }tdLd d|i }t	t
|d }}dM}|j}| }||v }|std%|fd&||ft|dt v st|rt|ndt|t|d' }tdNd) d*|i }t	t
|d } } }}dS )Oz:Test API input validation with security pattern detection.Tr       )typerequired
min_length
max_length   ra   r   )r   	camera_idcamera_nametestuser123123456789012zTest Camerar   r   r   r   z"Valid input should pass validationr   r   NrF   z!Valid input should not have errorrG   )z%(py0)s == %(py2)srz   
valid_datar   r`   z(Valid input should be returned unchanged
>assert %(py4)sr   r   Fz#Missing required fields should failre   rg   z(Missing fields should have error messageobaveznorP   rR   rS   z(Should have required field error messagerV   rW   xyTest	prekratak2xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxu   predugačakr   123451234567890123z#Length validation should fail for: )zD%(py0)s in %(py6)s
{%(py6)s = %(py4)s
{%(py4)s = %(py2)s.lower
}()
}expected_error)r   r`   r   r   zShould have length error for: r   r   z<script>alert("xss")</script>z'; DROP TABLE cameras; --z UNION SELECT password FROM userszjavascript:alert("xss")zonload=alert("xss")z#Malicious input should be blocked: z#Malicious input should have error: zneispravna vrijednostz%Should have invalid value error for: l   2}r z0Type conversion should work for compatible typesr   z'Camera ID should be converted to stringr\   r]   strr_   znot a dictionaryz!Non-dict input should be rejectedzneispravni podacizShould have invalid data error)r   r	   r#   r$   r%   r&   r'   r(   r)   r*   r+   rh   r]   )test_schemar   r   rF   rz   r5   r6   r7   r8   @py_format3r   incomplete_datarm   rn   ro   rp   rq   length_testsr   r   r   r   r   r   malicious_inputsmalicious_datatype_conversion_datainvalid_datar@   r@   rA   test_validate_api_input  sz   




r   c                  C   s  G dd d} |  }t |}g d}|D ]X}|j}||v }|shtd|fd||fdt v s4t|r9t|nddt v sEt|rJt|ndt|d }td	| d
 d|i }t	t
|d }}q|jd }	g d}
|
D ]O}||	v }|std|fd||	fdt v st|rt|nddt v st|	rt|	ndd }td| d d|i }t	t
|d}qx|jd }d}||k}|std|fd||ft|t|d }tdd
 d|i }t	t
|d } }}|jd }d}||k}|s9td|fd||ft|t|d }tdd
 d|i }t	t
|d } }}d}|jd  }||v }|sutd|fd!||ft|t|d }td"d
 d|i }t	t
|d } }}|  }d#|jd$< t |}d$}|j}||v}|std%|fd&||ft|d't v st|rt|nd't|d( }td)d* d+|i }t	t
|d } }}dS ),z/Test security headers middleware functionality.c                   @   s   e Zd Zdd ZdS )z6test_security_headers_middleware.<locals>.MockResponsec                 S   s
   i | _ d S )N)headers)selfr@   r@   rA   __init__  s   
z?test_security_headers_middleware.<locals>.MockResponse.__init__N)__name__
__module____qualname__r  r@   r@   r@   rA   MockResponse  s    r  )Content-Security-PolicyX-Frame-OptionsX-Content-Type-OptionsX-XSS-ProtectionzReferrer-PolicyzPermissions-PolicyrP   )z/%(py0)s in %(py4)s
{%(py4)s = %(py2)s.headers
}headerenhanced_responser   z"Required security header missing: r   r   Nr  )	zdefault-src 'self'zscript-src 'self'zstyle-src 'self'zimg-src 'self'zfont-src 'self'zconnect-src 'self'zframe-ancestors 'none'zbase-uri 'self'zform-action 'self')z%(py0)s in %(py2)s	directivecspr   zCSP directive missing: r   r   r  DENYrG   r   r   z#X-Frame-Options should deny framingr	  nosniffzShould prevent MIME sniffingz
mode=blockr
  )z%(py1)s in %(py4)sz#XSS protection should block attackszFlask/2.0.1 Werkzeug/2.0.1Serverrx   )z3%(py1)s not in %(py5)s
{%(py5)s = %(py3)s.headers
}enhanced)rT   r   r   zServer header should be removedr   rU   )r
   r   r#   r$   r%   r&   r'   r(   r)   r*   r+   )r  responser  required_headersr  r   r6   r   r   r  csp_directivesr  r   rm   r5   response_with_serverr  rn   r8   rp   r@   r@   rA    test_security_headers_middleware  s"   	
vxx
r  ) __doc__builtinsr%   _pytest.assertion.rewrite	assertionrewriter#   pytestr-   r   r   !app_modules.security_enhancementsr   r   r   r   r   r   r   r	   r
   marksecurityrB   ru   r   r   r   r   r   r   r  r@   r@   r@   rA   <module>   s0    ",
9
T
5
W

3

^