
    yPj$                        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 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      Zy)    )annotationsN)	lru_cache)
SSLContext)Any)	HTTPErrorURLError)urlparse   )PyJWKPyJWKSet)decode_complete)PyJWKClientConnectionErrorPyJWKClientError)JWKSetCachec                      e Zd Z	 	 	 	 	 	 	 d		 	 	 	 	 	 	 	 	 	 	 	 	 	 	 d
dZddZdddZdddZddZddZe	dd       Z
y)PyJWKClientNc	                f   |i }t        |      j                  j                         }	|	dvrt        d|	d      || _        d| _        || _        || _        || _        |r%|dk  rt        d| d      t        |      | _        nd| _        |r$ t        |      | j                        }
|
| _        yy)	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
        N)httphttpszInvalid JWKS URI scheme z(: only 'http' and 'https' are supported.r   z/Lifespan must be greater than 0, the input is "")maxsize)r	   schemelowerr   urijwk_set_cacheheaderstimeoutssl_contextr   r   get_signing_key)selfr   
cache_keysmax_cached_keyscache_jwk_setlifespanr   r   r   r   r   s              G/root/$HERMES_HOME/venv/lib/python3.12/site-packages/jwt/jwks_client.py__init__zPyJWKClient.__init__   s    j ?G
 #%%++-**"*6* 5! "  15& 1}&EhZqQ  "-X!6D!%D@i@AUAUVO#2D 	     c                   	 t         j                  j                  | j                  | j                        }t         j                  j                  || j                  | j                        5 }t        j                  |      }ddd       | j                   | j                   j#                         S # 1 sw Y   2xY w# t        t        f$ r5}t        |t              r|j                          t        d| d      |d}~ww xY 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.
        )urlr   )r   contextNz'Fail to fetch data from the url, err: "r   )urllibrequestRequestr   r   urlopenr   r   jsonloadr   TimeoutError
isinstancer   closer   r   put)r    rresponsejwk_setes        r%   
fetch_datazPyJWKClient.fetch_dataj   s    	&&488T\\&JA''4<<1A1A (  .))H-. )""7+#. . ,' 	!Y'	,9!A>	s0   A+C  -B4C  4B=9C   D0C??Dc                    d}| j                   |s| j                   j                         }|| j                         }t        |t              st        d      t        j                  |      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   getr9   r2   dictr   r   	from_dict)r    refreshdatas      r%   get_jwk_setzPyJWKClient.get_jwk_set   sc     )'%%))+D<??$D$%"#STT!!$''r'   c                    | j                  |      }|j                  D cg c]  }|j                  dv r|j                  r|  }}|st	        d      |S c c}w )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.
        )sigNz2The JWKS endpoint did not contain any signing keys)r@   keyspublic_key_usekey_idr   )r    r>   r7   jwk_set_keysigning_keyss        r%   get_signing_keyszPyJWKClient.get_signing_keys   si     ""7+  '||
))]:{?Q?Q 
 
 "#WXX
s   #Ac                    | j                         }| j                  ||      }|s5| j                  d      }| j                  ||      }|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   )rH   	match_kidr   )r    kidrG   signing_keys       r%   r   zPyJWKClient.get_signing_key   sl     ,,.nn\37000>L..s;K&B3%qI  r'   c                j    t        |ddi      }|d   }| j                  |j                  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
        verify_signatureF)optionsheaderrK   )decode_tokenr   r;   )r    token
unverifiedrP   s       r%   get_signing_key_from_jwtz$PyJWKClient.get_signing_key_from_jwt   s:     "%2De1LM
H%##FJJu$566r'   c                @    d}| D ]  }|j                   |k(  s|} |S  |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)rE   )rG   rK   rL   keys       r%   rJ   zPyJWKClient.match_kid   s:      	CzzS !	
 r'   )F   Ti,  N   N)r   strr!   boolr"   intr#   rZ   r$   floatr   zdict[str, Any] | Noner   r\   r   zSSLContext | None)returnr   )F)r>   rZ   r]   r   )r>   rZ   r]   list[PyJWK])rK   rY   r]   r   )rR   zstr | bytesr]   r   )rG   r^   rK   rY   r]   zPyJWK | None)__name__
__module____qualname__r&   r9   r@   rH   r   rT   staticmethodrJ    r'   r%   r   r      s     !!")-)-V3V3 V3 	V3
 V3 V3 'V3 V3 'V3p>(.287  r'   r   )
__future__r   r/   urllib.requestr+   	functoolsr   sslr   typingr   urllib.errorr   r   urllib.parser	   api_jwkr   r   api_jwtr   rQ   
exceptionsr   r   r   r   r   rc   r'   r%   <module>rn      s5    "      , ! $ 4 D &e er'   