
    piD                     &   U 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mZm	Z	m
Z
mZmZmZmZmZ ddlmZ ddlmZ ddlmZ ddlmZ dd	lmZmZ dd
lmZ  G d ded      Zej<                  ej<                  ej>                  ej>                  ej@                  ej@                  ej@                  ej@                  ejB                  ejB                  ejB                  ejB                  dZ"ee#ee$gdf   f   e%d<    ejL                  ejN                  dk  rdnd      Z(dZ)e	eed   df      e%d<    e* e+e"jY                                     Z-e	ee#df      e%d<    e.h d      Z/e	e
e#      e%d<   de#de#fdZ0de#de#fdZ1de#dee#e#f   fd Z2 G d! d"      Z3y)#av  
Digest authentication middleware for aiohttp client.

This middleware implements HTTP Digest Authentication according to RFC 7616,
providing a more secure alternative to Basic Authentication. It supports all
standard hash algorithms including MD5, SHA, SHA-256, SHA-512 and their session
variants, as well as both 'auth' and 'auth-int' quality of protection (qop) options.
    N)	CallableDictFinal	FrozenSetListLiteralTuple	TypedDictUnion)URL   )hdrs)ClientError)ClientHandlerType)ClientRequestClientResponse)Payloadc                   T    e Zd ZU eed<   eed<   eed<   eed<   eed<   eed<   eed<   y)	DigestAuthChallengerealmnonceqop	algorithmopaquedomainstaleN)__name__
__module____qualname__str__annotations__     g/opt/services/ai/voice_agent/venv/lib/python3.12/site-packages/aiohttp/client_middleware_digest_auth.pyr   r   $   s%    JJ	HNKKJr#   r   F)total)MD5zMD5-SESSSHAzSHA-SESSSHA256zSHA256-SESSzSHA-256zSHA-256-SESSSHA512zSHA512-SESSzSHA-512zSHA-512-SESSzhashlib._HashDigestFunctions)      z:(?:^|\s|,\s*)(\w+)\s*=\s*(?:"((?:[^"\\]|\\.)*)"|([^\s,]+))z>(?:^|\s|,\s*)((?>\w+))\s*=\s*(?:"((?:[^"\\]|\\.)*)"|([^\s,]+)))r   r   r   r   r   r   r   .CHALLENGE_FIELDSSUPPORTED_ALGORITHMS>   urir   r   cnoncer   responseusernameQUOTED_AUTH_FIELDSvaluereturnc                 &    | j                  dd      S )z,Escape double quotes for HTTP header values."\"replacer4   s    r$   escape_quotesr<   u   s    ==e$$r#   c                 &    | j                  dd      S )z-Unescape double quotes in HTTP header values.r8   r7   r9   r;   s    r$   unescape_quotesr>   z   s    ==$$r#   headerc           	          t         j                  |       D ci c](  \  }}}|j                         x}r||rt        |      n|* c}}}S c c}}}w )a  
    Parse key-value pairs from WWW-Authenticate or similar HTTP headers.

    This function handles the complex format of WWW-Authenticate header values,
    supporting both quoted and unquoted values, proper handling of commas in
    quoted values, and whitespace variations per RFC 7616.

    Examples of supported formats:
      - key1="value1", key2=value2
      - key1 = "value1" , key2="value, with, commas"
      - key1=value1,key2="value2"
      - realm="example.com", nonce="12345", qop="auth"

    Args:
        header: The header value string to parse

    Returns:
        Dictionary mapping parameter names to their values
    )_HEADER_PAIRS_PATTERNfindallstripr>   )r?   key
quoted_valunquoted_valstripped_keys        r$   parse_header_pairsrH      sZ    , .C-J-J6-R )C\IIK'L' 	Zoj1\Q  s   -Ac            	           e Zd ZdZ	 ddedededdfdZded	ed
ee	e
d   f   defdZd	edefdZdedefdZdededefdZy)DigestAuthMiddlewarea  
    HTTP digest authentication middleware for aiohttp client.

    This middleware intercepts 401 Unauthorized responses containing a Digest
    authentication challenge, calculates the appropriate digest credentials,
    and automatically retries the request with the proper Authorization header.

    Features:
    - Handles all aspects of Digest authentication handshake automatically
    - Supports all standard hash algorithms:
      - MD5, MD5-SESS
      - SHA, SHA-SESS
      - SHA256, SHA256-SESS, SHA-256, SHA-256-SESS
      - SHA512, SHA512-SESS, SHA-512, SHA-512-SESS
    - Supports 'auth' and 'auth-int' quality of protection modes
    - Properly handles quoted strings and parameter parsing
    - Includes replay attack protection with client nonce count tracking
    - Supports preemptive authentication per RFC 7616 Section 3.6

    Standards compliance:
    - RFC 7616: HTTP Digest Access Authentication (primary reference)
    - RFC 2617: HTTP Authentication (deprecated by RFC 7616)
    - RFC 1945: Section 11.1 (username restrictions)

    Implementation notes:
    The core digest calculation is inspired by the implementation in
    https://github.com/requests/requests/blob/v2.18.4/requests/auth.py
    with added support for modern digest auth features and error handling.
    loginpassword
preemptiver5   Nc                    |t        d      |t        d      d|v rt        d      || _        |j                  d      | _        |j                  d      | _        d| _        d| _        i | _        || _        g | _	        y )Nz"None is not allowed as login valuez%None is not allowed as password value:z8A ":" is not allowed in username (RFC 1945#section-11.1)utf-8r#   r   )

ValueError
_login_strencode_login_bytes_password_bytes_last_nonce_bytes_nonce_count
_challenge_preemptive_protection_space)selfrK   rL   rM   s       r$   __init__zDigestAuthMiddleware.__init__   s     =ABBDEE%<WXX&+*/,,w*?-5__W-E!$/1!+,.r#   methodurlbodyr#   c           
        #$K   | j                   }d|vrt        d      d|vrt        d      |d   }|d   }|st        d      |j                  dd      }|j                  dd	      }|j                         }	|j                  d
d      }
|j	                  d      }|j	                  d      }t        |      j                  }d}d}|rxddhj                  |j                  d      D ch c]#  }|j                         s|j                         % c}      }|st        d|       d|v rdnd}|j	                  d      }|	t        vr$t        d|	 ddj                  t                     t        |	   $dt        dt        f$fd#dt        dt        dt        f#fd}dj                  | j                  || j                  f      }|j                          d| j	                         }|dk(  rFt!        |t"              r|j%                          d{   }n|} #|      }dj                  ||f      } #|      } #|      }|| j&                  k(  r| xj(                  dz  c_        nd| _        || _        | j(                  d}|j	                  d      }t+        j,                  dj                  t/        | j(                        j	                  d      |t1        j2                         j	                  d      t5        j6                  d      g            j9                         dd  }|j	                  d      }|	j                         j;                  d!      r #dj                  |||f            }|r dj                  |||||f      } |||      }n ||dj                  ||f            }t=        | j>                        t=        |      t=        |      ||jA                         |d"}|
rt=        |
      |d
<   |r||d<   ||d#<   ||d$<   g } |jC                         D ];  \  }!}"|!tD        v r| jG                  |! d%|" d&       &| jG                  |! d'|"        = d(dj                  |        S c c}w 7 `w))a  
        Build digest authorization header for the current challenge.

        Args:
            method: The HTTP method (GET, POST, etc.)
            url: The request URL
            body: The request body (used for qop=auth-int)

        Returns:
            A fully formatted Digest authorization header string

        Raises:
            ClientError: If the challenge is missing required parameters or
                         contains unsupported values

        r   z:Malformed Digest auth challenge: Missing 'realm' parameterr   z:Malformed Digest auth challenge: Missing 'nonce' parameterzBSecurity issue: Digest auth challenge contains empty 'nonce' valuer    r   r&   r   rP   r#   authzauth-int,zEDigest auth error: Unsupported Quality of Protection (qop) value(s): z/Digest auth error: Unsupported hash algorithm: z. Supported algorithms: z, xr5   c                 L     |       j                         j                         S )z<RFC 7616 Section 3: Hash function H(data) = hex(hash(data)).)	hexdigestrS   )rd   hash_fns    r$   Hz'DigestAuthMiddleware._encode.<locals>.H  s    1:'')0022r#   sdc                 6     dj                  | |f            S )zDRFC 7616 Section 3: KD(secret, data) = H(concat(secret, ":", data)).   :)join)ri   rj   rh   s     r$   KDz(DigestAuthMiddleware._encode.<locals>.KD   s    TYY1v&''r#   rl   rO   Nr   08x      z-SESS)r2   r   r   r/   r1   r   ncr0   z="r7   =zDigest )$rX   r   getupperrS   r   path_qsintersectionsplitrC   r*   rm   r.   bytesrT   rU   
isinstancer   as_bytesrV   rW   hashlibsha1r    timectimeosurandomrf   endswithr<   rR   decodeitemsr3   append)%r[   r]   r^   r_   	challenger   r   qop_rawalgorithm_originalr   r   nonce_bytesrealm_bytespathr   	qop_bytesq
valid_qopsrn   A1A2entity_bytesentity_hashHA1HA2ncvaluencvalue_bytesr0   cnonce_bytesnoncebitresponse_digestheader_fieldspairsfieldr4   rh   rg   s%                                      @@r$   _encodezDigestAuthMiddleware._encode   s    & OO	)#L  )#L 
 '"'" T  --r*&]];>&,,.	x, ll7+ll7+3x 	 *-::$+MM#$6Dq!'')DJ ![\c[de  !+j 8*fC

7+IO+A) M))-3G)H(IK  )3	3 	35 	3	(% 	(E 	(e 	(
 YY));8L8LMNq'..0*$(%)]]_4#L/KB,-Bee $000" !D!,&&s+w/ HH))*11':JJL''0JJqM		
 )+cr	 }}W- ??%%g.DIIsK>?@C yym\9cJH !h/O diic0B&CDO &doo6"5)"5)'..0+
 &3F&;M(# #&M% ")M$&,M(# )//1 	1LE5**wbq12waw/0		1 5)*++S E<  5s&   C%Q6)Q.?Q.DQ6Q3I Q6c                     t        |      }| j                  D ]H  }|j                  |      st        |      t        |      k(  s|d   dk(  r y|t        |         dk(  sH y y)z
        Check if the given URL is within the current protection space.

        According to RFC 7616, a URI is in the protection space if any URI
        in the protection space is a prefix of it (after both have been made absolute).
        /TF)r    rZ   
startswithlen)r[   r^   request_str	space_strs       r$   _in_protection_spacez)DigestAuthMiddleware._in_protection_spacev  sk     #h// 		I)))4;3y>1Yr]c5I3y>*c1		 r#   r1   c           
      P   |j                   dk7  ry|j                  j                  dd      }|sy|j                  d      \  }}}|sy|j	                         dk7  ry|syt        |      x}syi | _        t        D ]%  }|j                  |      x}s|| j                  |<   ' |j                  j                         }	| j                  j                  d      x}
rg | _
        |
j                         D ]  }|j                  d      }|j                  d	      r=| j                  j                  t        |	j!                  t#        |                         b| j                  j                  t        t#        |                    nt        |	      g| _
        t%        | j                        S )
z
        Takes the given response and tries digest-auth, if needed.

        Returns true if the original request must be resent.
        i  Fzwww-authenticatera    digestr   r7   r   )statusheadersrt   	partitionlowerrH   rX   r-   r^   originrZ   rx   rC   r   r   r    rm   r   bool)r[   r1   auth_headerr]   sepr   header_pairsr   r4   r   r   r/   s               r$   _authenticatez"DigestAuthMiddleware._authenticate  s    ??c!&&**+=rB*44S9W<<>X% !37 ;;; % 	/E$((//u/).&	/
 $$&__((2262%'D"||~ Aiin>>#&**11#fkk#c(6K2LM **11#c#h-@A '*&k]D" DOO$$r#   requesthandlerc                   K   d}t        d      D ]  }|dkD  s3| j                  r{| j                  ro| j                  |j                        rT| j                  |j                  |j                  |j                         d{   |j                  t        j                  <    ||       d{   }| j                  |      r n |J |S 7 J7 !w)zRun the digest auth middleware.N   r   )rangerY   rX   r   r^   r   r]   r_   r   r   AUTHORIZATIONr   )r[   r   r   r1   retry_counts        r$   __call__zDigestAuthMiddleware.__call__  s       8 	K Q  OO--gkk:<@LLNNGKK= 7 2 23
 %W--H %%h/%	* ###7
 .s*   A=C?C
 *C*C+C
CC)T)r   r   r   __doc__r    r   r\   r   r   r   r   r   r   r   r   r   r   r   r"   r#   r$   rJ   rJ      s    D  	// / 	/
 
/4a,a, #a,+0'#,1F+Ga,	a,F  (9%n 9% 9%v$/@	r#   rJ   )4r   r|   r   resysr~   typingr   r   r   r   r   r   r	   r
   r   yarlr   ra   r   client_exceptionsr   client_middlewaresr   client_reqrepr   r   payloadr   r   md5r}   sha256sha512r*   r    ry   r!   compileversion_inforA   r-   tuplesortedkeysr.   	frozensetr3   r<   r>   rH   rJ   r"   r#   r$   <module>r      s    	 	 
 
 
 
   * 1 8 )5  ;;<<nn>>~~NNnn>>~~NNBc8UG_$<==> " #


'! B	J <	 %	QRTWW   05VO<P<P<R5S/T eE#s(O, T -6I- E)C.) 
% % %
%3 %3 %
s tCH~ 6F Fr#   