o
    sg$                     @   s$  d dl Z d dlZd dlZd dl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
mZmZ d dlmZ d dlmZmZ d dlmZmZmZmZmZmZmZmZmZmZ d dlmZ e Z ej!ded	Z"G d
d deZ#G dd deZ$dd Z%de&fddZ'de#de&fddZ(G dd dZ)dS )    N)	urlencode)HTTPExceptionstatus)RSAAlgorithm)	BaseModelEmailStr)
ACCESS_TOKENCOGNITO_CLIENT_IDCOGNITO_CLIENT_SECRETCOGNITO_DOMAINCOGNITO_LOGOUT_REDIRECT_URICOGNITO_REDIRECT_URICOGNITO_REGIONCOGNITO_USER_POOL_IDID_TOKENREFRESH_TOKEN)UserServicezcognito-idp)region_namec                   @   s.   e Zd ZU eed< eed< eed< eed< dS )CreateUserRequestemail
first_name	last_nameroleN)__name__
__module____qualname__r   __annotations__str r   r   1/var/www/html/XCapMarket/services/auth_service.pyr      s
   
 r   c                   @   s6   e Zd ZU eed< eed< eed< eed< eed< dS )TokenResponseaccess_tokenid_tokenrefresh_token
expires_in
token_typeN)r   r   r   r   r   intr   r   r   r   r    &   s   
 r    c                  C   s(   dt  dt d} t| }| d S )Nzhttps://cognito-idp.z.amazonaws.com/z/.well-known/jwks.jsonkeys)r   r   requestsgetjson)keys_urlresponser   r   r   get_cognito_public_keys.   s   
r-   tokenc              
      s   zTt | }|d  t }t fdd|D d }|s!tdddtt|}dd l	}t j
| |dgtd	d
}|dd}t|	 }|| }	|	dkrRtd|	d |W S  tyi }
 z	tdt|
d|
d }
~
ww )Nkidc                 3   s     | ]}|d   kr|V  qdS )r/   Nr   ).0kkey_idr   r   	<genexpr>;   s    z%validate_jwt_token.<locals>.<genexpr>i  zInvalid tokenstatus_codedetailr   RS256
   )
algorithmsaudienceleewayiatu.   ⚠️ WARNING: Your server clock is behind byzseconds.)jwtget_unverified_headerr-   nextr   r   from_jwkr*   dumpstimedecoder	   r)   r&   print	Exceptionr   )r.   headerspublic_keyskey
public_keyrC   payloadr=   current_timetime_differenceer   r2   r   validate_jwt_token4   s8   
rO   	user_datatemporary_passwordc              
      s(  z\t jt| jd| jddddg| jrd| jdgng | jr'd| jdgng |d}|di }|d	g }d
d |D }td| j  d|d|d|d|ddW S  t j	j
yr } ztddd|d}~w ty } ztdt|  tddt| d|d}~ww )z
    Creates a new user in Cognito user pool with the specified email and temporary password.
    The user will be required to change their password on first login.
    r   NameValueemail_verifiedtrue
given_namefamily_name)
UserPoolIdUsernameUserAttributesTemporaryPasswordUser
Attributesc                 S   s   i | ]	}|d  |d qS rR   r   )r0   attrr   r   r   
<dictcomp>|   s    z,create_user_cognito_pool.<locals>.<dictcomp>zCreated new user: zUser created successfullyrZ   )messageusernamer   r   r     z#User with this email already existsr5   NzError creating user:   )cognito_clientadmin_create_userr   r   r   r   r)   
XCM_loggerinfo
exceptionsUsernameExistsExceptionr   rF   errorr   )rP   rQ   r,   userattributes_listuser_attributesrN   r   r   r   create_user_cognito_pool[   sX   

ro   c                   @   sP   e Zd Zdd Zdd ZdefddZdefd	d
Zdd Zdd Z	dd Z
dS )AuthServicec                 C   s   d S )Nr   selfr   r   r   __init__   s   zAuthService.__init__c                    s"   t tddd}t dt| S )zGenerates Cognito login URLcodezopenid email profile)redirect_uri	client_idresponse_typescopez/login?)r   r	   r   r   )rr   paramsr   r   r   login   s   zAuthService.loginrt   c              
      s  |s	t dddt d}|  }dt|td}dd| d	}zzt 4 I d
H d}|j|||d4 I d
H @}|jdkrS|	 I d
H }t
d|  t |jdd|	 I d
H }	| |	I d
H W  d
  I d
H  W  d
  I d
H  W S 1 I d
H s}w   Y  W d
  I d
H  W d
S 1 I d
H sw   Y  W d
S  tjy }
 zt
dt|
 t|
 t ddt|
 d|
d
}
~
ww )z-Handles the OAuth callback and token exchangerc   z Authorization code not provided.r5   /oauth2/tokenauthorization_code)
grant_typerv   rt   ru   !application/x-www-form-urlencodedBasic zContent-TypeAuthorizationNdatarG      zToken exchange failed: zFailed to retrieve tokens.zCognito API error: %srd   z!Error connecting to Cognito API: )r   r   _create_basic_auth_headerr	   r   aiohttpClientSessionpostr   r*   rg   rk   _process_tokensClientErrorr   rE   )rr   rt   	token_urlauth_headerrK   rG   sessionr,   error_detailtokensrN   r   r   r   handle_callback   sZ   

2zAuthService.handle_callbackr#   c           
   
      s8  |s
t tjddt d}|  }tt|d}dd| d}z]t 4 I dH G}|j	|||d	4 I dH #}|
  | I dH }|W  d  I dH  W  d  I dH  W S 1 I dH s`w   Y  W d  I dH  W dS 1 I dH sww   Y  W dS  tjy }	 ztd
t|	 t tjdd|	d}	~	ww )z0Refreshes the access token using a refresh tokenzRefresh token not providedr5   r{   )r}   rv   r#   r~   r   r   Nr   zToken refresh failed: %szFailed to refresh token)r   r   HTTP_401_UNAUTHORIZEDr   r   r   r	   r   r   r   raise_for_statusr*   r   rg   rk   r   )
rr   r#   r   r   rK   rG   r   r,   r   rN   r   r   r   r#      sL   
2zAuthService.refresh_tokenc                 C   s   t  dt dt S )z Generates the Cognito logout URLz/logout?client_id=z&logout_uri=)r   r	   r   rq   r   r   r   get_logout_url   s   zAuthService.get_logout_urlc                 C   s(   t  dt }|d}t|dS )z3Creates the Basic Auth header for Cognito API calls:ascii)r	   r
   encodebase64	b64encoderD   )rr   auth_string
auth_bytesr   r   r   r      s   
z%AuthService._create_basic_auth_headerc           
         sr   | t}| t}| t}t|}t }||}| d}|r+d| d| nd| d| }	||	|dS )z2Process and validate tokens, create user if needed	isNewUserz/account/setup/user?id_token=z&access_token=z/project/listing?id_token=)r   frontend_urlr#   )r)   r   r   r   rO   r   get_or_create_user)
rr   r   r"   r!   r#   	user_infouser_serviceuser_responseis_new_userr   r   r   r   r      s    




zAuthService._process_tokensN)r   r   r   rs   rz   r   r   r#   r   r   r   r   r   r   r   rp      s    
/%rp   )*r   r*   loggingosurllib.parser   r   boto3r>   r(   fastapir   r   jwt.algorithmsr   pydanticr   r   configs.configr   r	   r
   r   r   r   r   r   r   r   services.user_servicer   	getLoggerrg   clientre   r   r    r-   r   rO   ro   rp   r   r   r   r   <module>   s4   0'
7