o
    iD                     @   s  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 deddZejejejejej ej ej ej ej!ej!ej!ej!dZ"ee#ee$gdf f e%d< e&ej'dk rdndZ(dZ)e	eed df  e%d< e*e+e", Z-e	ee#df  e%d< e.h dZ/e	e
e#  e%d< de#de#fddZ0de#de#fdd Z1d!e#dee#e#f fd"d#Z2G d$d% d%Z3dS )&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                   @   sF   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< dS )	DigestAuthChallengerealmnonceqop	algorithmopaquedomainstaleN)__name__
__module____qualname__str__annotations__ r    r    _/home/kim/smarthome/.venv/lib/python3.10/site-packages/aiohttp/client_middleware_digest_auth.pyr   $   s   
 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>   r   cnoncer   urir   usernameresponseQUOTED_AUTH_FIELDSvaluereturnc                 C      |  ddS )z,Escape double quotes for HTTP header values."\"replacer1   r    r    r!   escape_quotesu      r9   c                 C   r3   )z-Unescape double quotes in HTTP header values.r5   r4   r6   r8   r    r    r!   unescape_quotesz   r:   r;   headerc                    s    fddt | D S )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
    c                    s0   i | ]\}}}|    r |rt|n|qS r    )stripr;   ).0keyZ
quoted_valZunquoted_valZstripped_keyr    r!   
<dictcomp>   s    
z&parse_header_pairs.<locals>.<dictcomp>)_HEADER_PAIRS_PATTERNfindall)r<   r    r@   r!   parse_header_pairs   s   
rD   c                	   @   s   e Zd ZdZ	ddedededdfdd	Zd
ededee	e
d f defddZdedefddZdedefddZdededefddZdS )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.
    Tloginpassword
preemptiver2   Nc                 C   sp   |d u rt d|d u rt dd|v rt d|| _|d| _|d| _d| _d| _i | _|| _g | _	d S )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-8    r   )

ValueError
_login_strencode_login_bytes_password_bytes_last_nonce_bytes_nonce_count
_challenge_preemptive_protection_space)selfrF   rG   rH   r    r    r!   __init__   s   
zDigestAuthMiddleware.__init__methodurlbodyrK   c           "   
      sJ  | j }d|vrtdd|vrtd|d }|d }|s"td|dd}|dd	}| }	|d
d}
|d}|d}t|j}d}d}|rrddhdd |dD }|setd| d|v rkdnd}|d}|	t	vrtd|	 dd
t t	|	 dtdtffdd dtdtdtf fdd}d
| j|| jf}|  d|  }|dkrt|tr| I d H }n|} |}d
||f} |} |}|| jkr|  jd!7  _nd!| _|| _| jd"}|d}td
t| jd|t dtd#g d d$ }|d}|	 d%r. d
|||f}|rAd
|||||f}|||}n
||d
||f}t| jt|t||| |d&}|
rft|
|d
< |ru||d< ||d'< ||d(< g }|  D ]!\} }!| t!v r|"|  d)|! d* q{|"|  d+|!  q{d,d
| S )-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   rJ   rK   authzauth-intc                 S   s   h | ]
}|  r|  qS r    )r=   )r>   qr    r    r!   	<setcomp>  s    z/DigestAuthMiddleware._encode.<locals>.<setcomp>,zEDigest auth error: Unsupported Quality of Protection (qop) value(s): z/Digest auth error: Unsupported hash algorithm: z. Supported algorithms: z, xr2   c                    s    |    S )z<RFC 7616 Section 3: Hash function H(data) = hex(hash(data)).)	hexdigestrN   )r`   )hash_fnr    r!   H  s   z'DigestAuthMiddleware._encode.<locals>.Hsdc                    s    d | |fS )zDRFC 7616 Section 3: KD(secret, data) = H(concat(secret, ":", data)).   :)join)rd   re   )rc   r    r!   KD   s   z(DigestAuthMiddleware._encode.<locals>.KDrf   rI   Nr   08x      z-SESS)r.   r   r   r-   r/   r   ncr,   z="r4   =zDigest )#rS   r   getupperrN   r   Zpath_qsintersectionsplitr'   rg   r+   bytesrO   rP   
isinstancer   as_bytesrQ   rR   hashlibsha1r   timectimeosurandomra   endswithr9   rM   decodeitemsr0   append)"rV   rX   rY   rZ   	challenger   r   Zqop_rawZalgorithm_originalr   r   Znonce_bytesZrealm_bytespathr   Z	qop_bytesZ
valid_qopsrh   A1A2Zentity_bytesZentity_hashHA1HA2ncvalueZncvalue_bytesr,   Zcnonce_bytesnoncebitZresponse_digestZheader_fieldspairsfieldr1   r    )rc   rb   r!   _encode   s   








	


zDigestAuthMiddleware._encodec                 C   s\   t |}| jD ]$}||sqt|t|ks|d dkr  dS |t| dkr+ dS qdS )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   rU   
startswithlen)rV   rY   Zrequest_strZ	space_strr    r    r!   _in_protection_spacev  s   

z)DigestAuthMiddleware._in_protection_spacer/   c                 C   s  |j dkrdS |jdd}|sdS |d\}}}|sdS | dkr&dS |s*dS t| }s2dS i | _tD ]}|| }rE|| j|< q7|j	 }	| jd }
rg | _
|
 D ]$}|d}|d	rt| j
t|	t| qZ| j
tt| qZn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-authenticater[    digestr   r4   r   )statusheadersrn   	partitionlowerrD   rS   r*   rY   originrU   rq   r=   r   r~   r   rg   r   bool)rV   r/   auth_headerrX   sepr   Zheader_pairsr   r1   r   r   r-   r    r    r!   _authenticate  s<   





z"DigestAuthMiddleware._authenticaterequesthandlerc                    s   d}t dD ]1}|dks| jr*| jr*| |jr*| |j|j|jI dH |jt	j
< ||I dH }| |s8 nq|dus?J |S )zRun the digest auth middleware.N   r   )rangerT   rS   r   rY   r   rX   rZ   r   r   ZAUTHORIZATIONr   )rV   r   r   r/   Zretry_countr    r    r!   __call__  s&   

zDigestAuthMiddleware.__call__)T)r   r   r   __doc__r   r   rW   r   r
   r   r   r   r   r   r   r   r   r   r    r    r    r!   rE      s>    "

 $;rE   )4r   ru   ry   resysrw   typingr   r   r   r   r   r   r   r	   r
   Zyarlr   r[   r   Zclient_exceptionsr   Zclient_middlewaresr   Zclient_reqrepr   r   payloadr   r   md5rv   sha256sha512r'   r   rr   r   compileversion_inforB   r*   tuplesortedkeysr+   	frozensetr0   r9   r;   rD   rE   r    r    r    r!   <module>   s\    	, 

$