Ë
    LµCjV  ã                   óÀ   — d Z ddl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mZ ddlmZ  e	«       Z ee«      Z edd	d
¬«      fdedefd„Z G d„ d«      Zdedefd„Zy)uõ  
Security primitives: API key authentication and rate limiting.

For a client-facing production system, you need at minimum:
1. API key auth â€” so only authorized callers (the client's frontend/app)
   can hit your endpoints. Without this, anyone who finds your server's
   IP can hammer your LLM budget and ML compute for free.
2. Rate limiting â€” prevents both abuse and accidental self-DoS (e.g. a
   buggy frontend retry loop).

This is deliberately simple (static API keys + Redis-backed rate limiter)
rather than full OAuth2/JWT, because the brief is a backend service
consumed by the client's own application, not a multi-tenant public API.
If the client later needs per-user auth, JWT can be layered on top of
this without restructuring anything.
é    N)ÚHeaderÚHTTPExceptionÚRequest)ÚRedis)Úget_settings)ÚAuthenticationErrorÚRateLimitExceededError)Ú
get_logger.z	X-API-KeyzClient API key)ÚaliasÚdescriptionÚ	x_api_keyÚreturnc              ƒ   óä   K  — t         j                  }|s4t         j                  r"t        j	                  d«       t        dd¬«      ‚| S | |vr!t        j                  d«       t        d¬«      ‚| S ­w)z‡
    Dependency injected into every protected route.
    Rejects the request before any business logic runs if the key is invalid.
    z0No API keys configured in production environmentz'Service misconfigured. Contact support.z%VALID_API_KEYS is empty in production)ÚmessageÚdetailz%Rejected request with invalid API keyzInvalid or missing API key)r   )ÚsettingsÚvalid_api_keys_listÚis_productionÚloggerÚcriticalr   Úwarning)r   Ú
valid_keyss     ú>C:\Crop_Prediction\Backend\crop-ai-system\app\core\security.pyÚverify_api_keyr      sp   è ø€ ô ×-Ñ-€Jáô ×!Ò!Ü�O‰OÐNÔOÜ%ØAØ>ôð ð Ðà˜
Ñ"Ü�‰Ð>Ô?Ü!Ð*FÔGÐGàÐùs   ‚A.A0c                   ó0   — e Zd ZdZdedefd„Zdeddfd„Zy)	ÚRedisRateLimiterzÄ
    Sliding-window rate limiter backed by Redis, so it works correctly
    across multiple Gunicorn worker processes (in-memory counters would
    not, since each worker has its own memory).
    ÚredisÚlimit_per_minutec                 ó    — || _         || _        y )N)r   Úlimit)Úselfr   r   s      r   Ú__init__zRedisRateLimiter.__init__A   s   € ØˆŒ
Ø%ˆ�
ó    Ú
identifierr   Nc              ƒ   ó¦  K  — d|› dt        t        j                  «       dz  «      › �}	 | j                  j                  |«      ƒ d {  –—† }|dk(  r$| j                  j	                  |d«      ƒ d {  –—†  || j                  kD  rt        dd| j                  i¬«      ‚y 7 ŒV7 Œ/# t
        $ r"}t        j                  d|› �«       Y d }~y d }~ww xY w­w)	Nz
ratelimit:ú:é<   é   z(Rate limiter Redis error, failing open: z:Too many requests. Please slow down and try again shortly.r   )r   Úextra)
ÚintÚtimer   ÚincrÚexpireÚ	Exceptionr   Úerrorr    r	   )r!   r$   ÚkeyÚcurrentÚexcs        r   ÚcheckzRedisRateLimiter.checkE   sÄ   è ø€ Ø˜:˜, a¬¬D¯I©I«K¸2Ñ,=Ó(>Ð'?Ð@ˆð	Ø ŸJ™JŸO™O¨CÓ0×0ˆGØ˜!Š|Ø—j‘j×'Ñ'¨¨RÓ0×0Ð0ð �T—Z‘ZÒÜ(ØTØ)¨4¯:©:Ð6ôð ð  ð 1øà0ùÜò 	ô �L‰LÐCÀCÀ5ÐIÔJÜûð		üsR   ‚'CªB# ÁBÁ	(B# Á1B!Á2B# Á6)CÂB# Â!B# Â#	CÂ,C	ÃCÃ	CÃC)	Ú__name__Ú
__module__Ú__qualname__Ú__doc__r   r*   r"   Ústrr3   © r#   r   r   r   :   s-   „ ñð&˜eð &°só &ð cð ¨dô r#   r   Úrequestc              ƒ   óÂ   K  — | j                   j                  t        j                  «      }|rd|dd › �S | j                  r| j                  j
                  nd}d|› �S ­w)z’
    Prefer the API key as the rate-limit identifier (per-client fairness)
    falling back to IP if the key is somehow absent at this layer.
    zkey:Né   Úunknownzip:)ÚheadersÚgetr   ÚAPI_KEY_HEADERÚclientÚhost)r:   Úapi_keyÚclient_hosts      r   Úget_client_identifierrE   X   s\   è ø€ ð
 �o‰o×!Ñ!¤(×"9Ñ"9Ó:€GÙØ�g˜c˜r�l�^Ð$Ð$Ø)0¯ª�'—.‘.×%Ò%¸Y€KØ��ÐÐùs   ‚AA)r7   r+   Úfastapir   r   r   Úredis.asyncior   Úapp.core.configr   Úapp.core.exceptionsr   r	   Úapp.core.logging_configr
   r   r4   r   r8   r   r   rE   r9   r#   r   ú<module>rK      ss   ðñó" ç 2Ñ 2Ý å (ß KÝ .á‹>€Ù	�HÓ	€ñ ˜C {Ð@PÔQñØðàó÷6ñ ð<	¨ð 	°Sô 	r#   