a
    ng%                     @   sP  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
mZ d dlmZmZmZ d dlZd dlZd dlZd dlmZmZ d dlZd dlZd dlZd dlmZ d d	lmZ e  e Ze Zed
dZ ddgddgdZ!ej"ee!e  ddgdgd eddZ#dZ$dZ%eddZ&eddeddedded d!d"dd#d$Z'G d%d& d&eZ(G d'd( d(eZ)d)d* Z*ee&fe+d+d,d-Z,e-d.d/d0Z.e/d1e(d2d3d4Z0e/d5e(d2d6d7Z1e2d8ee,fe+d9d:d;Z3e/d<ee,fe)e+d=d>d?Z4e2d@ee,fe+e+dAdBdCZ5e6dDkrLd dl7Z7e7j8edEdFdG dS )H    )FastAPIHTTPExceptionDepends)CORSMiddleware)OAuth2PasswordBearer)DictAnyOptional)	BaseModel	validatorFieldN)datetime	timedelta)load_dotenv)get_game_validatorENVIRONMENTdevelopmentzhttp://localhost:3000zhttp://127.0.0.1:3000zhttps://iammrfrank.netzhttp://iammrfrank.net)r   
productionT*)Zallow_originsZallow_credentialsZallow_methodsZallow_headersZJWT_SECRET_KEYzyour-secret-key-hereZHS256i  token)ZtokenUrlZDB_HOST	localhostZDB_USERZidlegameZDB_PASSWORDZ3w3dCXqhVDl4aB0neAIfO7DZDB_NAMEZidle_game_dbZutf8mb4Zutf8mb4_unicode_ci)hostuserpasswordZdatabasecharsetZuse_unicodeZ	collationc                   @   sX   e Zd ZU eddddZeed< edddZeed< edd	d
 Z	eddd Z
dS )
UserCreate.      )
min_length
max_lengthusername   )r   r   c                 C   s   t d|std|S )Nz^[a-zA-Z0-9_-]+$zDUsername can only contain letters, numbers, underscores, and hyphensrematch
ValueErrorclsv r)   /var/www/html/idle/server.pyvalidate_usernameD   s    zUserCreate.validate_usernamec                 C   s(   |  stdtd|r$td|S )NzPassword cannot be emptyz[;<>&\']z$Password contains invalid characters)stripr%   r#   searchr&   r)   r)   r*   validate_passwordJ   s
    zUserCreate.validate_passwordN)__name__
__module____qualname__r   r    str__annotations__r   r   r+   r.   r)   r)   r)   r*   r   @   s   

r   c                   @   sv   e Zd ZU eed< eed< eed< eeef ed< eddd Z	eddd Z
edd	d
 Zeddd ZdS )SaveDatauserId	timestampversionstatec                 C   s   |dkrt d|S )Nr   zUser ID must be positive)r%   r&   r)   r)   r*   validate_user_idY   s    zSaveData.validate_user_idc                 C   s,   t t  d }||d kr(td|S )N  i z!Timestamp cannot be in the future)intr   utcnowr6   r%   )r'   r(   current_timer)   r)   r*   validate_timestamp_   s    zSaveData.validate_timestampc                 C   s   t d|std|S )Nz^\d+\.\d+\.\d+$z/Invalid version format. Must be in format X.Y.Zr"   r&   r)   r)   r*   validate_versionf   s    zSaveData.validate_versionc              
   C   sP   zt d|i |W S  tyJ } ztdt| W Y d }~n
d }~0 0 d S )Nr8   zInvalid game state: )game_validatorZvalidate_save_data	Exceptionr%   r2   )r'   r(   er)   r)   r*   validate_game_statel   s
    zSaveData.validate_game_stateN)r/   r0   r1   r;   r3   r2   r   r   r   r9   r>   r?   rC   r)   r)   r)   r*   r4   S   s   



r4   c               
   C   s`   zt jjf i t} | W S  tyZ } z*tdt|  tdddW Y d }~n
d }~0 0 d S )NzDatabase connection error:   zDatabase connection failedstatus_codeZdetail)mysqlZ	connectorconnect	DB_CONFIGrA   printr2   r   )connrB   r)   r)   r*   get_dbu   s    rL   )r   c              
      sn   z6t j| ttgd}|d}|d u r2tddd|W S  t jyh } ztdddW Y d }~n
d }~0 0 d S )N)Z
algorithmssub  zInvalid authentication tokenrE   )jwtdecode
SECRET_KEY	ALGORITHMgetr   ZJWTError)r   payloaduser_idrB   r)   r)   r*   get_current_user}   s    
rV   )datac                 C   s8   |   }t ttd }|d|i tj|tt	dS )N)minutesexp)	algorithm)
copyr   r<   r   ACCESS_TOKEN_EXPIRE_MINUTESupdaterO   encoderQ   rR   )rW   Z	to_encodeZexpirer)   r)   r*   create_access_token   s    r_   z/api/auth/register)r   c              
      s2  t  }|jdd}zztdd | jD r8tddd|d| jf | r\tdd	dt }t	| j
d
|}|d| j|f |  |j}tdt|i}|| j|dW W |  |  S  ty } z$|  tdt|dW Y d }~n
d }~0 0 W |  |  n|  |  0 d S )NT
dictionaryc                 s   s   | ]}|  V  qd S )N)isspace).0charr)   r)   r*   	<genexpr>       zregister.<locals>.<genexpr>i  z"Username cannot contain whitespacerE   z(SELECT id FROM users WHERE username = %szUsername already registeredutf-8z;INSERT INTO users (username, password_hash) VALUES (%s, %s)rM   r5   r    r   rD   )rL   cursoranyr    r   executefetchonebcryptZgensaltZhashpwr   r^   commitZ	lastrowidr_   r2   closerA   rollback)r   rK   ri   ZsaltZhashed_passwordrU   access_tokenrB   r)   r)   r*   register   s>    
(
rr   z/api/auth/loginc                    s   t  }|jdd}z|d| jf | }|s<tdddt| j	d|d 	dsftdddt
d	t|d
 i}|d
 |d |dW |  |  S |  |  0 d S )NTr`   zASELECT id, username, password_hash FROM users WHERE username = %srN   zInvalid username or passwordrE   rg   Zpassword_hashrM   idr    rh   )rL   ri   rk   r    rl   r   rm   Zcheckpwr   r^   r_   r2   ro   )r   rK   ri   Zdb_userrq   r)   r)   r*   login   s0      rt   z/api/auth/verify)current_userc                    sp   t  }|jdd}zF|d| f | }|s:tddd| |d dW |  |  S |  |  0 d S )	NTr`   z(SELECT username FROM users WHERE id = %srN   zUser not foundrE   r    )r5   r    )rL   ri   rk   rl   r   ro   )ru   rK   ri   r   r)   r)   r*   verify_token   s"      rv   z	/api/save)	save_dataru   c              
      s  t | j|krtdddt }| }zz~t| j}|d|f |	 }|rl|d| j
| j||f n|d|| j
| j|f |  ddd	W W |  |  S  ty } z$|  td
t |dW Y d }~n
d }~0 0 W |  |  n|  |  0 d S )N  z$Not authorized to save for this userrE   zA
            SELECT id FROM save_data WHERE user_id = %s
        z
                UPDATE save_data 
                SET save_timestamp = %s, version = %s, state_json = %s
                WHERE user_id = %s
            z
                INSERT INTO save_data (user_id, save_timestamp, version, state_json)
                VALUES (%s, %s, %s, %s)
            ZsuccesszSave successful)statusmessagerD   )r2   r5   r   rL   ri   jsondumpsr8   rk   rl   r6   r7   rn   ro   rA   rp   )rw   ru   rK   ri   
state_jsonZexisting_saverB   r)   r)   r*   	save_game   s:    (
r~   z/api/save/{user_id})rU   ru   c              
      s  | |krt dddt }|jdd}zz||d| f | }|sttt  d dd d	W W |	  |	  S |d
 |d t
|d d	W W |	  |	  S  ty } z.tdt|  t dt|dW Y d }~n
d }~0 0 W |	  |	  n|	  |	  0 d S )Nrx   z"Not authorized to access this saverE   Tr`   z
            SELECT save_timestamp as timestamp, version, state_json 
            FROM save_data 
            WHERE user_id = %s
        r:   z1.0.0)r6   r7   r8   r6   r7   r}   zLoad error: rD   )r   rL   ri   rk   rl   r;   r   r<   r6   ro   r{   loadsrA   rJ   r2   )rU   ru   rK   ri   saverB   r)   r)   r*   get_save  s>    
(
r   __main__z0.0.0.0i@  )r   port)9Zfastapir   r   r   Zfastapi.middleware.corsr   Zfastapi.securityr   typingr   r   r	   Zpydanticr
   r   r   rO   rm   Zmysql.connectorrG   r   r   r#   r{   osdotenvr   Zgame_settings_validatorr   appr@   getenvr   ZCORS_ORIGINSZadd_middlewarerQ   rR   r\   Zoauth2_schemerI   r   r4   rL   r2   rV   dictr_   Zpostrr   rt   rS   rv   r~   r   r/   uvicornrunr)   r)   r)   r*   <module>   sz   	




"
&&#
