o
    m=8jbJ                     @   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 ddl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Z-de de fd d!Z.d"e dee e f fd#d$Z/G d%d& d&Z0d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)FinalLiteral	TypedDict)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   l/home/nk/hobo-godmode/plappi-mvp/.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>   urir   r   cnoncer   responseusernameQUOTED_AUTH_FIELDSvaluereturnc                 C      |  ddS )z,Escape double quotes for HTTP header values."\"replacer,   r   r   r   escape_quotesl      r4   c                 C   r.   )z-Unescape double quotes in HTTP header values.r0   r/   r1   r3   r   r   r   unescape_quotesq   r5   r6   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   )stripr6   ).0key
quoted_valunquoted_valstripped_keyr   r   
<dictcomp>   s    
z&parse_header_pairs.<locals>.<dictcomp>)_HEADER_PAIRS_PATTERNfindall)r7   r   r=   r   parse_header_pairsv   s   
rB   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	d B 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 )DigestAuthMiddlewarea1  
    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

    Origin scoping:
    The credentials are scoped to the origin of the first request the
    middleware handles. A request to a different origin is passed through
    untouched, so it never receives a digest response computed from those
    credentials, unless that origin falls within a protection space the
    anchor origin advertised through the RFC 7616 ``domain`` directive. Make
    the first request through the middleware against the intended origin, as
    the anchor is pinned to it and not reset for the life of the instance.

    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
preemptiver-   Nc                 C   sv   |d u rt d|d u rt dd|v rt d|| _|d| _|d| _d| _d| _i | _|| _g | _	d | _
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_origin)selfrD   rE   rF   r   r   r   __init__   s   
zDigestAuthMiddleware.__init__methodurlbodyrI   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   rH   rI   authzauth-intc                 S   s   h | ]
}|  r|  qS r   )r8   )r9   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, xr-   c                    s    |    S )z<RFC 7616 Section 3: Hash function H(data) = hex(hash(data)).)	hexdigestrL   )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)rc   rd   )rb   r   r   KD$  s   z(DigestAuthMiddleware._encode.<locals>.KDre   rG   Nr   08x      z-SESS)r*   r   r   r'   r)   r   ncr(   z="r/   =zDigest )#rQ   r	   getupperrL   r   raw_path_qsintersectionsplitr"   rf   r&   bytesrM   rN   
isinstancer   as_bytesrO   rP   hashlibsha1r   timectimeosurandomr`   endswithr4   rK   decodeitemsr+   append)"rU   rW   rX   rY   	challenger   r   qop_rawalgorithm_originalr   r   nonce_bytesrealm_bytespathr   	qop_bytes
valid_qopsrg   A1A2entity_bytesentity_hashHA1HA2ncvaluencvalue_bytesr(   cnonce_bytesnoncebitresponse_digestheader_fieldspairsfieldr,   r   )rb   ra   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   rS   
startswithlen)rU   rX   request_str	space_strr   r   r   _in_protection_spacez  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 ]}|| }durG|| j|< q7|j	 }	| jd }
rg | _
|
 D ]$}|d	}|d
rv| j
t|	t| q\| j
tt| q\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-authenticaterZ    digestNr   r/   r   )statusheadersrm   	partitionlowerrB   rQ   r%   rX   originrS   rq   r8   r   r~   r   rf   r   bool)rU   r)   auth_headerrW   sepr   header_pairsr   r,   r   r   r'   r   r   r   _authenticate  s<   





z"DigestAuthMiddleware._authenticaterequesthandlerc                    s   |j  }| jdu r|| _n|| jkr!| |j s!||I dH S d}tdD ]1}|dks9| jrJ| jrJ| |j rJ| |j|j |j	I dH |j
tj< ||I dH }| |sX nq'|dus_J |S )zRun the digest auth middleware.N   r   )rX   r   rT   r   rangerR   rQ   r   rW   rY   r   r   AUTHORIZATIONr   )rU   r   r   r   r)   retry_countr   r   r   __call__  s0   



zDigestAuthMiddleware.__call__)T)r   r   r   __doc__r   r   rV   r   r   r   r   r   r   r   r   r
   r   r   r   r   r   rC      s.    +
" &;rC   )1r   ru   ry   resysrw   collections.abcr   typingr   r   r   yarlr   rZ   r   client_exceptionsr	   client_middlewaresr
   client_reqrepr   r   payloadr   r   md5rv   sha256sha512r"   dictr   rr   r   compileversion_infor@   r%   tuplesortedkeysr&   	frozensetr+   r4   r6   rB   rC   r   r   r   r   <module>   s^    	 

$