o
    ¤ó·i—!  ã                   @  sš   d dl m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lmZmZ ddlmZmZ dd	lmZ dd
lmZmZ ddlmZ G dd„ dƒZdS )é    )ÚannotationsN)Ú	lru_cache)Ú
SSLContext)ÚAny)Ú	HTTPErrorÚURLErroré   )ÚPyJWKÚPyJWKSet)Údecode_complete)ÚPyJWKClientConnectionErrorÚPyJWKClientError)ÚJWKSetCachec                   @  sj   e Zd Z							d.d/dd„Zd0dd„Zd1d2dd„Zd1d3d d!„Zd4d$d%„Zd5d(d)„Ze	d6d,d-„ƒZ
dS )7ÚPyJWKClientFé   Té,  Né   ÚuriÚstrÚ
cache_keysÚboolÚmax_cached_keysÚintÚcache_jwk_setÚlifespanÚfloatÚheadersúdict[str, Any] | NoneÚtimeoutÚssl_contextúSSLContext | Nonec	           
      C  sz   |du ri }|| _ d| _|| _|| _|| _|r)|dkr#td|› d�ƒ‚t|ƒ| _nd| _|r;t|d�| jƒ}	|	| _dS dS )u—  A client for retrieving signing keys from a JWKS endpoint.

        ``PyJWKClient`` uses a two-tier caching system to avoid unnecessary
        network requests:

        **Tier 1 â€” JWK Set cache** (enabled by default):
        Caches the entire JSON Web Key Set response from the endpoint.
        Controlled by:

        - ``cache_jwk_set``: Set to ``True`` (the default) to enable this
          cache. When enabled, the JWK Set is fetched from the network only
          when the cache is empty or expired.
        - ``lifespan``: Time in seconds before the cached JWK Set expires.
          Defaults to ``300`` (5 minutes). Must be greater than 0.

        **Tier 2 â€” Signing key cache** (disabled by default):
        Caches individual signing keys (looked up by ``kid``) using an LRU
        cache with **no time-based expiration**. Keys are evicted only when
        the cache reaches its maximum size. Controlled by:

        - ``cache_keys``: Set to ``True`` to enable this cache.
          Defaults to ``False``.
        - ``max_cached_keys``: Maximum number of signing keys to keep in
          the LRU cache. Defaults to ``16``.

        :param uri: The URL of the JWKS endpoint.
        :type uri: str
        :param cache_keys: Enable the per-key LRU cache (Tier 2).
        :type cache_keys: bool
        :param max_cached_keys: Max entries in the signing key LRU cache.
        :type max_cached_keys: int
        :param cache_jwk_set: Enable the JWK Set response cache (Tier 1).
        :type cache_jwk_set: bool
        :param lifespan: TTL in seconds for the JWK Set cache.
        :type lifespan: float
        :param headers: Optional HTTP headers to include in requests.
        :type headers: dict or None
        :param timeout: HTTP request timeout in seconds.
        :type timeout: float
        :param ssl_context: Optional SSL context for the request.
        :type ssl_context: ssl.SSLContext or None
        Nr   z/Lifespan must be greater than 0, the input is "ú")Úmaxsize)	r   Újwk_set_cacher   r   r   r   r   r   Úget_signing_key)
Úselfr   r   r   r   r   r   r   r   r$   © r&   úUC:\Users\psant\Downloads\PAF backend\school\venv\Lib\site-packages\jwt/jwks_client.pyÚ__init__   s$   5
ÿ
üzPyJWKClient.__init__Úreturnr   c              
   C  sØ   d}z\z,t jj| j| jd�}t jj|| j| jd��}t 	|¡}W d  ƒ n1 s)w   Y  W n  t
tfyO } zt|tƒrB| ¡  td|› d�ƒ|‚d}~ww |W | jdur^| j |¡ S S | jdurk| j |¡ w w )ae  Fetch the JWK Set from the JWKS endpoint.

        Makes an HTTP request to the configured ``uri`` and returns the
        parsed JSON response. If the JWK Set cache is enabled, the
        response is stored in the cache.

        :returns: The parsed JWK Set as a dictionary.
        :raises PyJWKClientConnectionError: If the HTTP request fails.
        N)Úurlr   )r   Úcontextz'Fail to fetch data from the url, err: "r!   )ÚurllibÚrequestÚRequestr   r   Úurlopenr   r   ÚjsonÚloadr   ÚTimeoutErrorÚ
isinstancer   Úcloser   r#   Úput)r%   Újwk_setÚrÚresponseÚer&   r&   r'   Ú
fetch_data_   s4   

ÿý€

ÿþ€ý
ÿÿzPyJWKClient.fetch_dataÚrefreshr
   c                 C  sH   d}| j dur|s| j  ¡ }|du r|  ¡ }t|tƒstdƒ‚t |¡S )aN  Return the JWK Set, using the cache when available.

        :param refresh: Force a fresh fetch from the endpoint, bypassing
            the cache.
        :type refresh: bool
        :returns: The JWK Set.
        :rtype: PyJWKSet
        :raises PyJWKClientError: If the endpoint does not return a JSON
            object.
        Nz.The JWKS endpoint did not return a JSON object)r#   Úgetr:   r3   Údictr   r
   Ú	from_dict)r%   r;   Údatar&   r&   r'   Úget_jwk_set|   s   


zPyJWKClient.get_jwk_setúlist[PyJWK]c                 C  s*   |   |¡}dd„ |jD ƒ}|stdƒ‚|S )a§  Return all signing keys from the JWK Set.

        Filters the JWK Set to keys whose ``use`` is ``"sig"`` (or
        unspecified) and that have a ``kid``.

        :param refresh: Force a fresh fetch from the endpoint, bypassing
            the cache.
        :type refresh: bool
        :returns: A list of signing keys.
        :rtype: list[PyJWK]
        :raises PyJWKClientError: If no signing keys are found.
        c                 S  s    g | ]}|j d v r|jr|‘qS ))ÚsigN)Zpublic_key_useÚkey_id)Ú.0Zjwk_set_keyr&   r&   r'   Ú
<listcomp>¡   s    ýýÿz0PyJWKClient.get_signing_keys.<locals>.<listcomp>z2The JWKS endpoint did not contain any signing keysN)r@   Úkeysr   )r%   r;   r6   Úsigning_keysr&   r&   r'   Úget_signing_keys“   s   
þzPyJWKClient.get_signing_keysÚkidr	   c                 C  sH   |   ¡ }|  ||¡}|s"| j dd�}|  ||¡}|s"td|› d�ƒ‚|S )a¡  Return the signing key matching the given ``kid``.

        If no match is found in the current JWK Set, the set is
        refreshed from the endpoint and the lookup is retried once.

        :param kid: The key ID to look up.
        :type kid: str
        :returns: The matching signing key.
        :rtype: PyJWK
        :raises PyJWKClientError: If no matching key is found after
            refreshing.
        T)r;   z,Unable to find a signing key that matches: "r!   N)rH   Ú	match_kidr   )r%   rI   rG   Úsigning_keyr&   r&   r'   r$   ¬   s   
ÿzPyJWKClient.get_signing_keyÚtokenústr | bytesc                 C  s(   t |ddid�}|d }|  | d¡¡S )aG  Return the signing key for a JWT by reading its ``kid`` header.

        Extracts the ``kid`` from the token's unverified header and
        delegates to :meth:`get_signing_key`.

        :param token: The encoded JWT.
        :type token: str or bytes
        :returns: The matching signing key.
        :rtype: PyJWK
        Zverify_signatureF)ÚoptionsÚheaderrI   N)Údecode_tokenr$   r<   )r%   rL   Z
unverifiedrO   r&   r&   r'   Úget_signing_key_from_jwtÈ   s   z$PyJWKClient.get_signing_key_from_jwtrG   úPyJWK | Nonec                 C  s&   d}| D ]}|j |kr|} |S q|S )a7  Find a key in *signing_keys* that matches *kid*.

        :param signing_keys: The list of keys to search.
        :type signing_keys: list[PyJWK]
        :param kid: The key ID to match.
        :type kid: str
        :returns: The matching key, or ``None`` if not found.
        :rtype: PyJWK or None
        N)rC   )rG   rI   rK   Úkeyr&   r&   r'   rJ   ×   s   
üzPyJWKClient.match_kid)Fr   Tr   Nr   N)r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r    )r)   r   )F)r;   r   r)   r
   )r;   r   r)   rA   )rI   r   r)   r	   )rL   rM   r)   r	   )rG   rA   rI   r   r)   rR   )Ú__name__Ú
__module__Ú__qualname__r(   r:   r@   rH   r$   rQ   ÚstaticmethodrJ   r&   r&   r&   r'   r      s     ÷
N

r   )Ú
__future__r   r0   Úurllib.requestr,   Ú	functoolsr   Ússlr   Útypingr   Úurllib.errorr   r   Zapi_jwkr	   r
   Zapi_jwtr   rP   Ú
exceptionsr   r   r#   r   r   r&   r&   r&   r'   Ú<module>   s    