
    lKj`'                       d Z ddlmZ ddl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mZ ddlmZ ddlmZmZ dZdZe G d	 d
             Ze G d d             Ze G d d             Z G d d      ZddZddZ	 	 d	 	 	 	 	 	 	 ddZddZy)uk  Minimal OAuth 2.0 Authorization Server for MCP spec compatibility.

Supports:
- RFC 8414  /.well-known/oauth-authorization-server  metadata
- RFC 7591  POST /oauth/register  (disabled — pre-provisioned clients only)
- RFC 7636  Authorization Code + PKCE (S256 required)
- GET  /oauth/authorize   authorization endpoint
- POST /oauth/token        token exchange
    )annotationsN)	dataclassfield)Request)JSONResponseRedirectResponsei  i,  c                  B    e Zd ZU ded<   dZded<    ee      Zded<   y)	RegisteredClientstr	client_idN
str | Noneclient_secret)default_factoryz	list[str]redirect_uris)__name__
__module____qualname____annotations__r   r   listr        o/Users/ahmed/devFolder/Ultron/claude-voice/.venv/lib/python3.12/site-packages/macos_mcp/infrastructure/oauth.pyr
   r
   !   s     N $M:$$T:M9:r   r
   c                  N    e Zd ZU ded<   ded<   ded<   ded<   ded<   dZded	<   y
)AuthorizationCoder   coder   redirect_uricode_challengecode_challenge_method        float
expires_atNr   r   r   r   r!   r   r   r   r   r   (   s(    
INJr   r   c                  0    e Zd ZU ded<   ded<   dZded<   y)AccessTokenr   tokenr   r   r    r!   Nr"   r   r   r   r$   r$   2   s    JNJr   r$   c                      e Zd ZdZddZy)
OAuthStorez1In-memory store for OAuth state (single-process).c                .    i | _         i | _        i | _        y )N)clientscodestokens)selfs    r   __init__zOAuthStore.__init__<   s    4635
.0r   N)returnNone)r   r   r   __doc__r-   r   r   r   r'   r'   9   s
    ;1r   r'   c                :   |dk(  r{t        j                  | j                  d            j                         }t	        j
                  |      j                  d      j                  d      }t        j                  ||      S |dk(  rt        j                  | |      S y)NS256ascii   =plainF)
hashlibsha256encodedigestbase64urlsafe_b64encoderstripdecodesecretscompare_digest)code_verifierr   methodr9   expecteds        r   _verify_pkcerC   G   s     4 4W =>EEG++F3::4@GGP%%h??%%m^DDr   c                ,   t         j                  j                  |       }|j                  dvs|j                  r|j
                  ry|j                  j                         }|dk(  ry	 t        j                  |      j                  S # t        $ r Y yw xY w)N>   httphttpsF	localhostT)urllibparseurlparseschemehostnamefragmentlower	ipaddress
ip_addressis_loopback
ValueError)r   parsedhosts      r   _is_loopback_redirect_urirU   Q   s}    \\""<0F}}--V__??  "D{##D)555 s   (B 	BBc                     rt               j                  <   d	fd}d	d}d	 fd}d	 fd}|dgf|dgf|dgf|dgfdS )
z@Return a dict of {path: (handler, methods)} for OAuth endpoints.)r   r   c           
     F   K   t         d ddgdgdgdgd      S w)N/oauth/authorize/oauth/tokenr   authorization_coder2   client_secret_post)issuerauthorization_endpointtoken_endpointresponse_types_supportedgrant_types_supported code_challenge_methods_supported%token_endpoint_auth_methods_supportedr   )requestr\   s    r   metadataz$build_oauth_routes.<locals>.metadataq   sG     )/0@&A!'5)/&:%;176J5K
  	s   !c                *   K   t        dddd      S w)Nregistration_disabledzsDynamic OAuth client registration is disabled. Configure --oauth-client-id and --oauth-client-secret on the server.errorerror_descriptioni  status_coderc   )rd   s    r   registerz$build_oauth_routes.<locals>.register|   s&     0[ 	
 		
s   c           	       K   | j                   }|j                  dd      }|j                  dd      }|j                  dd      }|j                  dd      }|j                  dd      }|j                  dd      }|d	k7  rt        d
did      S |st        dddd      S |dk7  rt        dddd      S t        |      st        dddd      S rst        dddd      S |k7  rt        d
did      S j                  |   }||j
                  vr|j
                  j                  |       t        j                  d      }	t        |	||||t        j                         t        z         j                  |	<   d|v rdnd}
| |
 dt        j                  j                  |	       }|r%|dt        j                  j                  |       z  }t!        |d      S w)Nr    r   response_typestater   r   r2   r   ri   unsupported_response_type  rk   invalid_requestzcode_challenge required (PKCE)rh   z"code_challenge_method must be S256z+redirect_uri must be a loopback http(s) URIserver_errorz0OAuth requires a configured client ID and secreti  invalid_client    )r   r   r   r   r   r!   ?&zcode=z&state=i.  )query_paramsgetr   rU   r)   r   appendr>   token_urlsafer   timeCODE_LIFETIMEr*   rH   rI   quoter   )rd   paramsr   r   rp   rq   r   r   clientr   seplocationconfigured_client_idconfigured_client_secretstores               r   	authorizez%build_oauth_routes.<locals>.authorize   s    %%JJ{B/	zz."5

?B7

7B'$4b9 &

+BF KF"*E FTWXX+Bbc 
 !F*+Bfg 
 )6+Bop 
 $+C(?qr 
 ,,*: ;MMy)v333  ''5$$R(-%)"7yy{]2
D L(cc"^C5fll.@.@.F-GH'&,,"4"4U";!<==Hc::s   GG c                  K   | j                   j                  dd      }d|v r$| j                          d {   }t        |      }nAd|v r| j	                          d {   }n$	 | j                          d {   }t        |      }|j                  d	d      d
k7  rt        ddid      S |j                  dd      }|j                  dd      }|j                  dd      }|j                  dd      }j                  j                  |      }|st        dddd      S |j                  |k7  rt        dddd      S |j                  |k7  rt        dddd      S t        j                         |j                  kD  rj                  |= t        dddd      S t        ||j                  |j                        st        dddd      S j                  |= j                  j                  |      }	|	r|	j                   st        ddid      S |j                  dd      }
|
r t#        j$                  |
|	j                         st        ddid      S t#        j&                  d      }t)        ||t        j                         t*        z         j,                  |<   t        |dt*        d      S 7 |7 W7 @# t
        $ r t        ddid      cY S w xY ww)Nzcontent-typero   z!application/x-www-form-urlencodedzapplication/jsonri   rt   rs   rk   
grant_typerZ   unsupported_grant_typer   r@   r   r   invalid_grantzunknown coderh   zclient_id mismatchzredirect_uri mismatchzcode expiredzPKCE verification failedrv   i  r   0   )r%   r   r!   Bearer)access_token
token_type
expires_in)headersr{   formdictjson	Exceptionr   r*   r   r   r~   r!   rC   r   r   r)   r   r>   r?   r}   r$   TOKEN_LIFETIMEr+   )rd   content_typer   body
code_valuer@   r   r   	auth_coder   provided_secretr   r   s               r   r%   z!build_oauth_routes.<locals>.token   s    **>2>.,> 'D:D</ 'DS$\\^+Dz 88L"%)==*B CQTUUXXfb)
"5HH["-	xx3KKOOJ/	)O]`  )+)@TUcf  !!\1)@WXfi  99;---J')O]`  M9+C+CYEdEde)@Z[il  KK
#""9-V11*: ;MM((?B7g&<&<_fNbNb&c*: ;MM,,R0%0yy{^3&
\" ("(
  	 ( ( , S#W.?$@cRRSsX   4KJ3'KJ6 K&J< 9J9:J< 	H+K6K9J< <KKKKGETPOST)z'/.well-known/oauth-authorization-serverz/oauth/registerrX   rY   )rd   r   )r
   r)   )r   r\   r   r   re   rm   r   r%   s   ````    r   build_oauth_routesr   c   sm     .>*2/
*+
	

9;vFR 5=ug3F$vh/&0)	 r   c                    | j                   j                  |      }|yt        j                         |j                  kD  r| j                   |= yy)zDReturn True if the token is a valid, non-expired OAuth access token.FT)r+   r{   r~   r!   )r   r%   ats      r   validate_oauth_tokenr     sB    			%	 B	zyy{R]]"LLr   )r@   r   r   r   rA   r   r.   bool)r   r   r.   r   )NN)r   r'   r\   r   r   r   r   r   )r   r'   r%   r   r.   r   )r0   
__future__r   r6   r:   rO   r>   r~   urllib.parserH   dataclassesr   r   starlette.requestsr   starlette.responsesr   r   r   r   r
   r   r$   r'   rC   rU   r   r   r   r   r   <module>r      s    #       ( & > ; ; ;      1 1
* (,+/	mmm %m )	mjr   