
    LCjV                         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 !!OO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DIIK2,=(>'?@	 JJOOC00G!|jj''R000 TZZ(T)4::6    10 	 LLCC5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\     
 oo!!("9"9:Ggcrl^$$)0'..%%YK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#   