
    _imS                     n   d dl Z d dlmZmZ d dlmZ d dlmZ d dlmZ d dl	Z	d dl
Z
d dlmZmZmZ d dlmZ d dlmZmZ d	 Z G d
 dej        e          Z G d dej                  Z G d dej                  Z G d dej                  Z G d dej                  Z G d dej                  ZdS )    N)datetimetimezone)	UserMixin)
SQLAlchemy)	validates)URLSafeTimedSerializerSignatureExpiredBadSignature)current_app)dblogin_managerc                  (    t          j                    S )u.   Génère un secret aléatoire pour TOTP (2FA).)pyotprandom_base32     )/var/www/html/MCyber-Diagnostic/models.pygenerate_2fa_secretr      s       r   c                   l    e Zd ZdZdZ ej         ej        d          dd           Z ej         ej        d          ddd	          Z	 ej         ej        d
          d          Z
 ej         ej        d          d          Z ej         ej        d          d          Z ej        ej        dd          Z ej        ej        dd          Z ej        ej        dd          Z ej         ej        d          ddd          Z ej        ej        dd          Z ej        ej        dd          Z ej        ej        dd          Z ej        ej        d          Z ej        ej        d d          Z ej        ej        d d d          Z ej         ej        d          d          Z ej        ej        dd          Z ej        ej        d          Z ej         ej        d           ej        d          dd          Z ej         ej        d           ej        d          dd          Z  ej!        d  ej"        deg          ddeg          Z# ej!        d  ej"        deg          de g           Z$ ej!        d!d"dd#$          Z% fd%Z& e'd&          d'             Z( e'd(          d)             Z) e'd*          d+             Z*d, Z+d:d/Z,e-d;d0            Z.d1 Z/d2 Z0d3 Z1d4 Z2d5 Z3d6 Z4d7 Z5e6d8             Z7d9 Z8 xZ9S )<Userux   
    Modèle représentant un utilisateur du système.
    Supporte 3 rôles : admin, manager, user (client final).
    users$   Tc                  B    t          t          j                              S Nstruuiduuid4r   r   r   <lambda>zUser.<lambda>)       DJLL)) r   primary_keydefaultx   Funiquenullableindex   r'         r#   r'      userr#   r'   r(      c                  >    t          j        t          j                  S r   r   nowr   utcr   r   r   r   zUser.<lambda>>       X\8R8R r   c                  >    t          j        t          j                  S r   r3   r   r   r   r   zUser.<lambda>A       X\22 r   c                  >    t          j        t          j                  S r   r3   r   r   r   r   zUser.<lambda>B       hl33 r   r#   onupdater'       users.idr'   r(   manager)remote_sideselectzsave-update, merge)backreflazycascadeforeign_keysparent)rC   rD   rF   Rapportauteurzall, delete-orphan)rC   rD   rE   c                      t          t          |           j        di | | j        st	                      | _        d S d S )Nr   )superr   __init__two_factor_secretr   )selfkwargs	__class__s     r   rL   zUser.__init__v   sO    "dD",,V,,,% 	;%8%:%:D"""	; 	;r   emailc                     |st          d          d}t          j        ||          st          d|           |                                                                S )Nu   L'email ne peut pas être videz0^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$zFormat d'email invalide : )
ValueErrorrematchlowerstrip)rN   keyrQ   email_regexs       r   validate_emailzUser.validate_email   sd     	?=>>>IxU++ 	CA%AABBB{{}}""$$$r   rolec                 f    g d}||vr(t          d| dd                    |                     |S )N)adminr@   r/   u   Rôle invalide : u   . Doit être : z, )rS   join)rN   rX   r[   allowed_roless       r   validate_rolezUser.validate_role   sI    444}$$```diiP]F^F^``aaar   company_namec                 z    |r"t          |          dk    rt          d          |r|                                nd S )Nr+   u5   Le nom d'entreprise ne peut dépasser 150 caractères)lenrS   rW   )rN   rX   names      r   validate_company_namezUser.validate_company_name   s?     	VCIIOOTUUU#-tzz|||-r   c                     | j         S )uI   Requis par Flask-Login pour vérifier si l'utilisateur peut se connecter.)is_active_accountrN   s    r   	is_activezUser.is_active   s    %%r     Nc                     |rt          |          nt          t          j        d                   }t          |          }|                    d| j        id          S )uA   Génère un token sécurisé pour réinitialiser le mot de passe.
SECRET_KEYuser_idpassword-reset)salt)r   r   config
Serializerdumpsid)rN   expires_sec
secret_keyrX   ss        r   get_reset_tokenzUser.get_reset_token   sO    !+Vc*ooo[5G5U1V1VsOOww	47+2BwCCCr   c                    |rt          |          nt          t          j        d                   }t          |          }	 |                    | d|          d         }t          |t                     rt          |          dk    rdS n# t          t          f$ r Y dS w xY wt          j
                            |          S )uA   Vérifie un token de réinitialisation et retourne l'utilisateur.rl   rn   )ro   max_agerm   r   N)r   r   rp   rq   loads
isinstancerc   r	   r
   r   queryget)tokenru   ry   rX   rv   rm   s         r   verify_reset_tokenzUser.verify_reset_token   s     ",Vc*ooo[5G5U1V1VsOO	gge*:GgLLYWG gs++ s7||r/A/At 0B !,/ 	 	 	44	 z~~g&&&s   AB
 
BBc                 ~    t           j                            | j                                      | j        d          S )u-   Retourne l'URI pour générer le QR code 2FA.zMCyber Consulting)rd   issuer_name)r   totpTOTPrM   provisioning_urirQ   rh   s    r   get_totp_urizUser.get_totp_uri   s9    zt566GG+ H 
 
 	
r   c                 b    t          j        | j                  }|                    |d          S )u8   Vérifie un code TOTP (2FA) avec fenêtre de tolérance.r1   )valid_window)r   r   rM   verify)rN   r~   r   s      r   verify_totp_codezUser.verify_totp_code   s*    z$011{{5q{111r   c                     | j         o| j        S )u/   Vérifie si l'utilisateur peut créer un audit.)rg   	can_auditrh   s    r   can_create_auditzUser.can_create_audit   s    %8$.8r   c                 8    | j         dk    o|j        | j        k    S )u6   Vérifie si cet utilisateur est le manager d'un autre.r@   )r[   
manager_idrs   )rN   r/   s     r   is_manager_ofzUser.is_manager_of   s    yI%D$/TW*DDr   c                     | j         dk    rg S t          j                            | j                                                  S )u1   Retourne tous les clients gérés par ce manager.r@   r   )r[   r   r|   	filter_byrs   allrh   s    r   get_all_clientszUser.get_all_clients   s;    9	!!Iz##tw#77;;===r   c                     | j         dk    rdS t          j                            | j                                                  dk    S )u%   Vérifie si ce manager a des clients.r@   Fr   r   )r[   r   r|   r   rs   countrh   s    r   has_clientszUser.has_clients   s@    9	!!5z##tw#77==??!CCr   c                 8    d| j          d| j         d| j         dS )Nz<User z (Role: z
, Active: )>)rQ   r[   rg   rh   s    r   __repr__zUser.__repr__   s*    [
[[DI[[AW[[[[r   c                 ,    | j         r| j         n| j        S )u   
        Retourne l'ID du propriétaire des données.
        - Si je suis le Manager Principal : retourne mon ID.
        - Si je suis un Membre d'équipe : retourne l'ID de mon parent.
        )	parent_idrs   rh   s    r   owner_idzUser.owner_id   s     "&<t~~TW<r   c                     | j         dk    rg S | j        }t          j                            |                                          S )uY   
        Retourne les clients gérés par l'équipe entière (Patron + Membres).
        r@   r   )r[   r   r   r|   r   r   )rN   	target_ids     r   get_team_clientszUser.get_team_clients   sF     9	!!I M	 z##y#99==???r   )rj   N)Nrj   ):__name__
__module____qualname____doc____tablename__r   ColumnStringrs   rQ   passwordra   logo_filenameBooleanshow_logo_on_reportsshow_company_name_on_reportsuse_manager_brandingr[   rg   r   Integermax_concurrent_sessionsDateTimeengagement_end_date
created_at
updated_atrM   two_factor_enabledTexttwo_factor_recovery_codes
ForeignKeyr   r   relationshiprC   clientsteam_membersrapportsrL   r   rZ   r`   re   ri   rw   staticmethodr   r   r   r   r   r   r   r   propertyr   r   __classcell__)rP   s   @r   r   r      s         M 
	"))
 
 
B BIibinnTENNNEry3%888H29YRYs^^d;;;LBIibinnt<<<M$29RZOOO#,29RZQV#W#W#W $29RZNNN 29YRYr]]FU$OOOD!	"*dUKKK	"*dUCCCI'bi
ANNN $")BK$???2;0R0R]bcccJ
2233	  J "	)")B--$???"2:uuMMM )	"'D A A A 	"j!!	  J 		"j!!	  I bo
92$777$ \  G #2?
8"666[	  L r$	  H; ; ; ; ; Yw% % % Yv   Y~. . .& & &D D D D ' ' ' \'(
 
 
2 2 29 9 9E E E> > >D D D\ \ \ = = X=@ @ @ @ @ @ @r   r   c                   
   e Zd ZdZdZ ej         ej        d          dd           Z ej        ej	        d dd	          Z
 ej         ej        d
          dd          Z ej        ej        d          Z ej        ej        d          Z ej        ej        d          Z ej         ej        d           ej        d          dd          Z ed          d             Z ed          d             ZdS )rH   uF   
    Modèle représentant un rapport d'audit de cybersécurité.
    r   r   Tc                  B    t          t          j                              S r   r   r   r   r   r   zRapport.<lambda>
  r    r   r!   c                  >    t          j        t          j                  S r   r3   r   r   r   r   zRapport.<lambda>  r8   r   Fr0   r+   Client Inconnur-   r*   r>   r?   score_totalc                     t          |t                    st          d          d|cxk    rdk    sn t          d| d          |S )Nu   Le score doit être un entierr   d   u+   Le score doit être entre 0 et 100 (reçu: ))r{   intrS   )rN   rX   scores      r   validate_scorezRapport.validate_score'  sa    %%% 	><===E    S    S5SSSTTTr   
nom_clientc                     |r|                                 sdS t          |          dk    rt          d          |                                 S )Nr   r+   u2   Le nom du client ne peut dépasser 150 caractères)rW   rc   rS   )rN   rX   noms      r   validate_nom_clientzRapport.validate_nom_client/  sK     	$#))++ 	$##s88c>>QRRRyy{{r   N)r   r   r   r   r   r   r   r   rs   r   date_creationr   r   r   r   raw_datapreconisations_jsonr   rm   r   r   r   r   r   r   rH   rH      sx         M 
	"))
 
 
B BI
22	  M 929S>>3CeTTTJ ")BJ777Kry4000H#")BGe<<< bi	"j!!	  G Y}   Y|    r   rH   c                      e Zd ZdZdZ ej         ej        d          dd           Z ej        ej	        d          Z
 ej         ej        d	          d
d          Z ej        ej        dd          Z ej        ej        d d          Z ej        ej        d d d          Z ed          d             Z ed          d             Zd ZdS )AnnouncementuN   
    Modèle représentant un bandeau d'information affiché globalement.
    announcementsr   Tc                  B    t          t          j                              S r   r   r   r   r   r   zAnnouncement.<lambda>D  r    r   r!   Fr*   r.   r   r-   c                  >    t          j        t          j                  S r   r3   r   r   r   r   zAnnouncement.<lambda>L  r8   r   c                  >    t          j        t          j                  S r   r3   r   r   r   r   zAnnouncement.<lambda>Q  r8   r   c                  >    t          j        t          j                  S r   r3   r   r   r   r   zAnnouncement.<lambda>R  r:   r   r;   targetc                 :    g d}||vrt          d|           |S )N)r   r@   r/   zCible invalide : rS   )rN   rX   r   allowed_targetss       r   validate_targetzAnnouncement.validate_targetV  s4    444((999:::r   messagec                     |r|                                 st          d          t          |          dk    rt          d          |                                 S )Nu!   Le message ne peut pas être videi  u,   Le message ne peut dépasser 500 caractèresrW   rS   rc   )rN   rX   r   s      r   validate_messagezAnnouncement.validate_message]  sX     	Bgmmoo 	B@AAAw<<#KLLL}}r   c                 H    d| j         d d          d| j         d| j         dS )Nz<Announcement    z... (Active: z
, Target: r   )rs   ri   r   rh   s    r   r   zAnnouncement.__repr__e  s3    ccc$.ccTXT_ccccr   N)r   r   r   r   r   r   r   r   rs   r   r   r   r   ri   r   r   r   r   r   r   r   r   r   r   r   r   ;  s]         $M		"))
 
 
B bi%000GRYyry}}eeDDDF	"*dUCCCI
22  J
 
2233	  J Yx   Yy  d d d d dr   r   c                      e Zd ZdZdZ ej         ej        d          dd           Z ej         ej        d          d	          Z	 ej         ej        d
          dd          Z
 ej         ej        d          d	          Z ej         ej        d          d	          Z ej        ej        d	          Z ej        ej        d d          Z ej         ej        d           ej        d          d	          Z ej        ddd          Z ed          d             Z ed          d             Zd ZdS )DocumentuA   
    Modèle représentant un document PDF téléchargeable.
    	documentsr   Tc                  B    t          t          j                              S r   r   r   r   r   r   zDocument.<lambda>u  r    r   r!   r+   Fr*   2   guider-   r,   c                  >    t          j        t          j                  S r   r3   r   r   r   r   zDocument.<lambda>  r8   r   r>   r   uploaded_documentsrB   rC   rD   categoryc                 :    g d}||vrt          d|           |S )N)r   cgvotheru   Catégorie invalide : r   )rN   rX   r   allowed_categoriess       r   validate_categoryzDocument.validate_category  s6    666---@h@@AAAr   titlec                     |r|                                 st          d          t          |          dk    rt          d          |                                 S )Nu   Le titre ne peut pas être vider+   u*   Le titre ne peut dépasser 150 caractèresr   )rN   rX   r   s      r   validate_titlezDocument.validate_title  sX     	@EKKMM 	@>???u::IJJJ{{}}r   c                 (    d| j          d| j         dS )Nz
<Document z (r   )r   r   rh   s    r   r   zDocument.__repr__  s    ;DJ;;$-;;;;r   N)r   r   r   r   r   r   r   r   rs   r   r   filenameoriginal_filenamer   	file_sizer   r   r   uploaded_byr   uploaderr   r   r   r   r   r   r   r   r   l  s          M		"))
 
 
B BIibinnu555Ery2%HHHHry3%888H!	)")C..5AAA	"*u555I
22  J
 ")	"j!!  K rv/C(SSSHYz   Yw  < < < < <r   r   c                   F   e Zd ZdZdZ ej         ej        d          dd           Z ej        ej	        d dd	          Z
 ej         ej        d
          dd          Z ej         ej        d          dd          Z ej         ej        d          d          Z ej         ej        d           ej        d          dd          Z ej         ej        d          d          Z ej         ej        d          d          Z ej         ej        d          d          Z ej        ej        d          Z ej        ej        d          Z ej        ej        d          Z ej        ej        dd          Z ej        ej	        d          Z ej         ej        d           ej        d          d          Z ej        degdd          Z ej        degd          Zd Zedd            Z edd            Z!d Z"dS )AuditLogu|   
    Logs d'audit pour traçabilité et debug.
    Séparation : Logs activité (INFO) vs Logs erreurs (ERROR/CRITICAL)
    
audit_logsr   Tc                  B    t          t          j                              S r   r   r   r   r   r   zAuditLog.<lambda>      C
DUDU r   r!   c                  >    t          j        t          j                  S r   r3   r   r   r   r   zAuditLog.<lambda>  s    x|HL7Q7Q r   Fr0   r.   r?   r   r   r*   r>   -   r,   r-   r   rB   )rF   rC   rD   )rF   rD   c                 8    d| j          d| j         d| j         dS )Nz
<AuditLog  z @ >)levelaction	timestamprh   s    r   r   zAuditLog.__repr__  s)    JDJJJJJJJJJr   Nc           
      `   t          d| ||||||          }t          j                            |           	 t          j                                         dS # t
          $ rK}t          j                                         t          j        	                    d|            Y d}~dS d}~ww xY w)u)   Helper pour logs INFO (activité normale)INFO)r  r   r  r   rm   r   
ip_address
user_agentzErreur sauvegarde log INFO: N
r   r   sessionaddcommit	Exceptionrollbackr   loggererror)	r   r  r   rm   r   ipr  loges	            r   log_infozAuditLog.log_info  s     !	
 	
 	
 	
s	IJ 	I 	I 	IJ!!!$$%GA%G%GHHHHHHHHH	Is   A 
B-"A B((B-ERRORc	                 b   t          || |||||||	  	        }	t          j                            |	           	 t          j                                         dS # t
          $ rK}
t          j                                         t          j        	                    d|
            Y d}
~
dS d}
~
ww xY w)z/Helper pour logs ERROR/CRITICAL (bugs, erreurs))	r  r   r  r   error_detailssuggested_fixrm   r   r
  zErreur sauvegarde log ERROR: Nr  )r   r  r   r  r  rm   r   r  r  r  r  s              r   	log_errorzAuditLog.log_error  s     ''

 

 

 	
s	JJ 	J 	J 	JJ!!!$$%HQ%H%HIIIIIIIII	Js   A 
B.#A B))B.c                     d| _         t          j        t          j                  | _        || _        t          j        	                                 dS )u!   Marquer une erreur comme résolueTN)
resolvedr   r4   r   r5   resolved_atresolved_byr   r  r  )rN   resolver_ids     r   mark_resolvedzAuditLog.mark_resolved  s?    #<55&

r   )NNNN)NNNNNr  )#r   r   r   r   r   r   r   r   rs   r   r  r  r   r  r   rm   r   r
  r  r   r   r  r  r   r  r  r   r   r/   resolverr   r   r  r  r"  r   r   r   r   r     s         !M	929R==d<U<U	V	V	VB	"+/Q/Q\aimnnnI BIibimme4@@@Ery2dCCCHRYyry~~666F bi		"}r}Z'@'@4W[\\\G	)")B--$777I929R==4888J929S>>D999J bi%000GBIbg555MBIbg555M ryUUCCCH")BK$777K")IBIbMM=2=+D+DtTTTK 2?6	<V^___Drv[MQQQHK K K I I I \I& J J J \J(    r   r   c                      e Zd ZdZdZ ej         ej        d          dd           Z ej         ej        d           ej	        d          dd	          Z
 ej         ej        d
          ddd          Z ej         ej        d          d          Z ej         ej        d
          d          Z ej         ej        d          d          Z ej         ej        d          d          Z ej        ej        d dd          Z ej        ej        d d          Z ej        ej        d          Z ej        ddd          Zd Zed             Zed             Zd ZdS )UserSessionuy   
    Tracker des sessions actives pour multi-connexion.
    Permet de gérer les limites de connexions simultanées.
    user_sessionsr   Tc                  B    t          t          j                              S r   r   r   r   r   r   zUserSession.<lambda>  r   r   r!   r>   Fr?   r,   r%   r  r*   r   c                  >    t          j        t          j                  S r   r3   r   r   r   r   zUserSession.<lambda>  r6   r   r0   c                  >    t          j        t          j                  S r   r3   r   r   r   r   zUserSession.<lambda>  s    8<;U;U r   r-   r   active_sessionsrB   r   c                 (    d| j          d| j         dS )Nz<UserSession z from r  )rm   r
  rh   s    r   r   zUserSession.__repr__  s    Et|EE4?EEEEr   c                  R   ddl m}  t          j                            t          j        t          j        t          j	                  k               
                                }|D ]}| j                            |           | j                                         t          |          S )u   Supprime les sessions expiréesr   )r   )
extensionsr   r%  r|   filter
expires_atr   r4   r   r5   r   r  deleter  rc   )r   expiredr  s      r   cleanup_expiredzUserSession.cleanup_expired  s     	"!!!!!#**;+AHLQYQ]D^D^+^__ccee 	' 	'GJg&&&&

7||r   c                     t                                            t           j                            |                                           S )z8Compte le nombre de sessions actives pour un utilisateurrm   )r%  r2  r|   r   r   r4  s    r   get_active_countzUserSession.get_active_count"  s<     	##%%% **7*;;AACCCr   c                     t          j        t          j                  | _        t
          j                                         dS )u$   Met à jour le timestamp d'activitéN)r   r4   r   r5   last_activityr   r  r  rh   s    r   update_activityzUserSession.update_activity(  s0    %\(,77

r   N)r   r   r   r   r   r   r   r   rs   r   rm   session_tokenr
  r  device_infolocationr   r   r7  r/  r   r/   r   r   r2  r5  r8  r   r   r   r%  r%    s         $M	929R==d<U<U	V	V	VBbi		"}r}Z'@'@5X\]]]GBIibinnTEQUVVVM 929R==4888J929S>>D999J")IBIcNNT:::Kry3$777H 2;0R0R]bjnoooJBIbk3U3U`efffM2;777J 2?6+<8LLLDF F F   \ D D \D
    r   r%  )r   r   r   flask_loginr   flask_sqlalchemyr   sqlalchemy.ormr   r   rT   itsdangerousr   rq   r	   r
   flaskr   r-  r   r   r   Modelr   rH   r   r   r   r%  r   r   r   <module>rB     s     ' ' ' ' ' ' ' ' ! ! ! ! ! ! ' ' ' ' ' ' $ $ $ $ $ $  				 ] ] ] ] ] ] ] ] ] ]       ( ( ( ( ( ( ( (! ! !Z@ Z@ Z@ Z@ Z@28Y Z@ Z@ Z@D5 5 5 5 5bh 5 5 5v+d +d +d +d +d28 +d +d +db0< 0< 0< 0< 0<rx 0< 0< 0<lT T T T Trx T T Tt/ / / / /"( / / / / /r   