
    3fiΉ                    x   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 d dl	m
Z
mZmZmZ d dlmZ erd dlmZ  ej$                  e      Zh dZ G d d	e      Z G d
 de      Z G d de      Z G d de      Z G d de      Z G d de      Z G d de      Z G d de      Z G d de      Z G d de      Zy)    )annotationsN)Path)OptionalProtocolUnionTYPE_CHECKING)
TokenCache)
Connection>   openidprofileoffline_accessc                       e Zd ZdZddZddZy)CryptographyManagerTypezAbstract cryptography managerc                     y N selfdatas     N/var/www/auto_recruiter/arenv/lib/python3.12/site-packages/O365/utils/token.pyencryptzCryptographyManagerType.encrypt           c                     y r   r   r   s     r   decryptzCryptographyManagerType.decrypt   r   r   N)r   strreturnbytes)r   r   r   r   )__name__
__module____qualname____doc__r   r   r   r   r   r   r      s    '..r   r   c                  @    e Zd ZdZeZ fdZedd       Zdd	 	 	 ddZ	ddddZ
ddddZd d	Zd!d
Zddd	 	 	 	 	 d"dZddd#dZddd#dZddd#dZddd	 	 	 	 	 d$dZd%dZd& fdZd'd& fdZd(dZd)dZddZd*ddZddZddZd'dd	 	 	 d+dZ xZS ),BaseTokenBackendzA base token storage classc                >    t         |           d| _        d | _        y )NF)super__init___has_state_changedcryptography_manager)r   	__class__s    r   r'   zBaseTokenBackend.__init__"   s    (-GK!r   c                ,    t        | j                        S )z$Does the token backend contain data.)bool_cacher   s    r   has_datazBaseTokenBackend.has_data(   s     DKK  r   Nusernamec                   | j                  |      }|y|j                  d      }|yt        |      }t        j                  j                  |      S )a'  
        Returns the current access token expiration datetime
        If the refresh token is present, then the expiration datetime is extended by 3 months
        :param str username: The username from which check the tokens
        :return dt.datetime or None: The expiration datetime
        r0   N
expires_on)get_access_tokengetintdtdatetimefromtimestamp)r   r1   access_tokenr3   s       r   token_expiration_datetimez*BaseTokenBackend.token_expiration_datetime-   sW     ,,h,?!%%l3
ZJ;;,,Z88r   c               n    | j                  |      }|yt        j                  j                         |kD  S )z
        Checks whether the current access token is expired
        :param str username: The username from which check the tokens
        :return bool: True if the token is expired, False otherwise
        r0   T)r;   r7   r8   now)r   r1   r;   s      r   token_is_expiredz!BaseTokenBackend.token_is_expiredB   s8     %)$B$BH$B$U!$,;;??$'@@@r   c               *    | j                  |      duS )z0Returns if the token backend has a refresh tokenr0   N)get_refresh_token)r   r1   s     r   token_is_long_livedz$BaseTokenBackend.token_is_long_livedN   s    %%x%8DDr   c                    t        | j                  t        j                  j                  d|i            }|r|d   j                  d      S t        j                  d|        y)zQGets the home_account_id string from the ACCOUNT cache for the specified usernamer1   queryr   home_account_idzNo account found for username: N)listsearchr	   CredentialTypeACCOUNTr5   logdebug)r   r1   results      r   _get_home_account_idz%BaseTokenBackend._get_home_account_idR   s_     KK
1199*hAWKX
 !9==!233II7zBCr   c                f    t        | j                  t        j                  j                              S )z9Returns a list of all accounts present in the token cache)rF   rG   r	   rH   rI   r.   s    r   get_all_accountsz!BaseTokenBackend.get_all_accounts^   s"    DKK
 9 9 A ABCCr   )r1   rE   c                   |r|rt        d      d}|d|i}|d|i}t        | j                  t        j                  j
                  |            }|r|d   S y)zEGets the account object for the specified username or home_account_idzTProvide nothing or either username or home_account_id to "get_account", but not bothNr1   rE   rC   r   )
ValueErrorrF   rG   r	   rH   rI   )r   r1   rE   rD   rL   s        r   get_accountzBaseTokenBackend.get_accountb   ss     f  *E&&8Edkk*";";"C"C5kQR!9r   c                   d}|| j                  |      }|rd|i}nyt        | j                  t        j                  j
                  |            }|r|d   S dS )z
        Retrieve the stored access token
        If username is None, then the first access token will be retrieved
        :param str username: The username from which retrieve the access token
        NrE   rC   r   )rM   rF   rG   r	   rH   ACCESS_TOKENr   r1   rD   rE   resultss        r   r4   z!BaseTokenBackend.get_access_tokenx   sd     "77AO*O<t{{:#<#<#I#IQV{WX$wqz.$.r   c                   d}|| j                  |      }|rd|i}nyt        | j                  t        j                  j
                  |            }|r|d   S dS )zRetrieve the stored refresh token
        If username is None, then the first access token will be retrieved
        :param str username: The username from which retrieve the refresh token
        NrE   rC   r   )rM   rF   rG   r	   rH   REFRESH_TOKENrU   s        r   r@   z"BaseTokenBackend.get_refresh_token   sh    
 "77AO*O<KK
11??uKM
 %wqz.$.r   c                   d}|| j                  |      }|rd|i}nyt        | j                  t        j                  j
                  |            }|r|d   S dS )zRetrieve the stored id token
        If username is None, then the first id token will be retrieved
        :param str username: The username from which retrieve the id token
        NrE   rC   r   )rM   rF   rG   r	   rH   ID_TOKENrU   s        r   get_id_tokenzBaseTokenBackend.get_id_token   sc    
 "77AO*O<t{{:#<#<#E#EU{ST$wqz.$.r   F)r1   remove_reservedc                   | j                  |      xs | j                  |      }|r@|j                  d      }|r-|j                  d      }|r|D cg c]  }|t        vs| }}|S yc c}w )a	  
        Retrieve the scopes the token (refresh first then access) has permissions on
        :param str username: The username from which retrieve the refresh token
        :param bool remove_reserved: if True RESERVED_SCOPES will be removed from the list
        r0   target N)r@   r4   r5   splitRESERVED_SCOPES)r   r1   r\   token
scopes_strscopesscopes          r   get_token_scopesz!BaseTokenBackend.get_token_scopes   s     &&&9 
T=R=R >S >
 8,J#))#."17X5;WeXFX Ys   A*!A*c                  | j                  |      }|syd|i}t        | j                  t        j                  j
                  |            }|D ]  }| j                  |        t        | j                  t        j                  j                  |            }|D ]  }| j                  |        t        | j                  t        j                  j                  |            }|D ]  }| j                  |        t        | j                  t        j                  j                  |            }|D ]  }| j                  |        d| _        y)z
        Removes all tokens and all related data from the token cache for the specified username.
        Returns success or failure.
        :param str username: The username from which remove the tokens and related data
        FrE   rC   T)rM   rF   rG   r	   rH   rZ   
remove_idtrT   	remove_atrX   	remove_rtrI   remove_accountr(   )	r   r1   rE   rD   rV   id_tokenr:   refresh_tokenaccounts	            r   remove_datazBaseTokenBackend.remove_data   s9    33H="O4 t{{:#<#<#E#EU{ST 	&HOOH%	& t{{:#<#<#I#IQV{WX# 	)LNN<(	) KK
11??uKM
 % 	*MNN=)	* t{{:#<#<#D#DE{RS 	)G(	) #'r   c                4    t        |   |fi | d| _        y)zAdd to the current cache.TN)r&   addr(   )r   eventkwargsr*   s      r   rq   zBaseTokenBackend.add   s    E$V$"&r   c                6    t         |   |||       d| _        y)zModify content in the cache.TN)r&   modifyr(   )r   credential_type	old_entrynew_key_value_pairsr*   s       r   ru   zBaseTokenBackend.modify   s    	3FG"&r   c                    | j                   5  d| _        | j                  j                  | j                  d      }| j
                  | j
                  j                  |      }|cddd       S # 1 sw Y   yxY w)z0Serialize the current cache state into a string.F   )indentN)_lockr(   
serializerdumpsr-   r)   r   )r   	token_strs     r   	serializezBaseTokenBackend.serialize   sh    ZZ 	&+D#--dkk!-DI((4 55==iH		 	 	s   AA..A7c                    | j                   5  d| _        | j                  | j                  j                  |      }|r| j                  j                  |      ni cddd       S # 1 sw Y   yxY w)zEDeserialize the cache from a state previously obtained by serialize()FN)r|   r(   r)   r   r}   loads)r   token_cache_states     r   deserializezBaseTokenBackend.deserialize   sf    ZZ 	Y&+D#((4$($=$=$E$EFW$X!?P4??(():;VX		Y 	Y 	Ys   AA$$A-c                    t         )z
        Abstract method that will retrieve the token data from the backend
        This MUST be implemented in subclasses
        NotImplementedErrorr.   s    r   
load_tokenzBaseTokenBackend.load_token   
    
 "!r   c                    t         )z
        Abstract method that will save the token data into the backend
        This MUST be implemented in subclasses
        r   r   forces     r   
save_tokenzBaseTokenBackend.save_token  r   r   c                    t         )z=Optional Abstract method to delete the token from the backendr   r.   s    r   delete_tokenzBaseTokenBackend.delete_token      !!r   c                    t         )zHOptional Abstract method to check for the token existence in the backendr   r.   s    r   check_tokenzBaseTokenBackend.check_token  r   r   c                    y)a	  
        This method is intended to be implemented for environments
        where multiple Connection instances are running on parallel.

        This method should check if it's time to refresh the token or not.
        The chosen backend can store a flag somewhere to answer this question.
        This can avoid race conditions between different instances trying to
        refresh the token at once, when only one should make the refresh.

        This is an example of how to achieve this:

            1. Along with the token store a Flag
            2. The first to see the Flag as True must transactional update it
               to False. This method then returns True and therefore the
               connection will refresh the token.
            3. The save_token method should be rewritten to also update the flag
               back to True always.
            4. Meanwhile between steps 2 and 3, any other token backend checking
               for this method should get the flag with a False value.

            | This method should then wait and check again the flag.
            | This can be implemented as a call with an incremental backoff
              factor to avoid too many calls to the database.
            | At a given point in time, the flag will return True.
            | Then this method should load the token and finally return False
              signaling there is no need to refresh the token.

            | If this returns True, then the Connection will refresh the token.
            | If this returns False, then the Connection will NOT refresh the token as it was refreshed by
             another instance or thread.
            | If this returns None, then this method has already executed the refresh and also updated the access
             token into the connection session and therefore the Connection does not have to.

            By default, this always returns True

        There is an example of this in the example's folder.



        :param con: the Connection instance passed by the caller. This is passed because maybe
         the locking mechanism needs to refresh the token within the lock applied in this method.
        :param username: The username from which retrieve the refresh token
        :return: | True if the Connection should refresh the token
                 | False if the Connection should not refresh the token as it was refreshed by another instance
                 | None if the token was refreshed by this method and therefore the Connection should do nothing.
        Tr   )r   conr1   s      r   should_refresh_tokenz%BaseTokenBackend.should_refresh_token  s    ` r   r   r,   )r1   Optional[str]r   zOptional[dt.datetime])r1   r   r   r,   )r1   r   r   r   )r   z
list[dict])r1   r   rE   r   r   Optional[dict])r1   r   r   r   )r1   r   r\   r,   r   zOptional[list])r1   r   r   r,   )r   Noner   )r   Union[bytes, str])r   r   r   dictF)r   zOptional[Connection]r1   r   r   zOptional[bool])r   r    r!   r"   jsonr}   r'   propertyr/   r;   r>   rA   rM   rO   rR   r4   r@   r[   rf   ro   rq   ru   r   r   r   r   r   r   r   __classcell__r*   s   @r   r$   r$      s   $JL ! !
 ,09(9	9* =A 
A @D E
D
 ,0RV(BO	, =A /" >B /$ 9= /" ,0(BF	(#J'
'
Y""""07;0'40@N0r   r$   c                  L     e Zd ZdZd fd	Zd Zd	dZd
d	dZd	dZd	dZ	 xZ
S )FileSystemTokenBackendz0A token backend based on files on the filesystemc                    t         |           t        |t              s|rt        |      n	t               }|j	                         r|| _        y|xs d}||z  | _        y)z
        Init Backend
        :param str or Path token_path: the path where to store the token
        :param str token_filename: the name of the token file
        zo365_token.txtN)r&   r'   
isinstancer   is_file
token_path)r   r   token_filenamer*   s      r   r'   zFileSystemTokenBackend.__init__K  sT     	*d+-7j)TVJ(DO+?/?N(>9DOr   c                ,    t        | j                        S r   )r   r   r.   s    r   __repr__zFileSystemTokenBackend.__repr__\  s    4??##r   c                H   | j                   j                         r|| j                   j                  d      5 }| j                  |j	                               }d|v rt        d      || _        t        j                  d| j                           ddd       yy# 1 sw Y   yxY w)z}
        Retrieves the token from the File System and stores it in the cache
        :return bool: Success / Failure
        rr:   zqThe token you are trying to load is not valid anymore. Please delete the token and proceed to authenticate again.zToken loaded from NTF)	r   existsopenr   readrQ   r-   rJ   rK   )r   
token_file
token_dicts      r   r   z!FileSystemTokenBackend.load_token_  s    
 ??!!#%%c* Bj!--joo.?@
!Z/$U  )		.t.?@AB B s   ABB!c                   | j                   sy|du r| j                  du ry	 | j                  j                  j	                         s&| j                  j                  j                  d       | j                  j                  d      5 }|j                  | j                                ddd       y# t        $ r"}t        j                  d|        Y d}~yd}~ww xY w# 1 sw Y   yxY w)z
        Saves the token cache dict in the specified file
        Will create the folder if it doesn't exist
        :param bool force: Force save even when state has not changed
        :return bool: Success / Failure
        FT)parentsToken could not be saved: Nw)r-   r(   r   parentr   mkdir	ExceptionrJ   errorr   writer   )r   r   er   s       r   r   z!FileSystemTokenBackend.save_tokenq  s     {{E>d55>	??))002&&,,T,:
 __!!#& 	/*T^^-.	/  	II21#67		/s$   A
B0  C0	C9CCC'c                n    | j                   j                         r| j                   j                          yy)zP
        Deletes the token file
        :return bool: Success / Failure
        TF)r   r   unlinkr.   s    r   r   z#FileSystemTokenBackend.delete_token  s*    
 ??!!#OO""$r   c                6    | j                   j                         S )zt
        Checks if the token exists in the filesystem
        :return bool: True if exists, False otherwise
        )r   r   r.   s    r   r   z"FileSystemTokenBackend.check_token  s    
 %%''r   )NNr   r   r   r    r!   r"   r'   r   r   r   r   r   r   r   s   @r   r   r   H  s$    ::"$$0(r   r   c                  (    e Zd ZdZd ZddZdddZy)MemoryTokenBackendz!A token backend stored in memory.c                     y)Nr   r   r.   s    r   r   zMemoryTokenBackend.__repr__      #r   c                     yNTr   r.   s    r   r   zMemoryTokenBackend.load_token      r   c                     yr   r   r   s     r   r   zMemoryTokenBackend.save_token  r   r   Nr   r   )r   r    r!   r"   r   r   r   r   r   r   r   r     s    +$r   r   c                  L     e Zd ZdZd fd	Zd Zd	dZd
d	dZd	dZd	dZ	 xZ
S )EnvTokenBackendz0A token backend based on environmental variable.c                D    t         |           |r|| _        yd| _        y)z
        Init Backend
        :param str token_env_name: the name of the environmental variable that will hold the token
        	O365TOKENN)r&   r'   token_env_name)r   r   r*   s     r   r'   zEnvTokenBackend.__init__  s#    
 	 1?nKr   c                ,    t        | j                        S r   )r   r   r.   s    r   r   zEnvTokenBackend.__repr__  s    4&&''r   c                    | j                   t        j                  v r>| j                  t        j                  j	                  | j                               | _        yy)zm
        Retrieves the token from the environmental variable
        :return bool: Success / Failure
        TF)r   osenvironr   r5   r-   r.   s    r   r   zEnvTokenBackend.load_token  sA    
 "**,**2::>>$:M:M+NODKr   c                    | j                   sy|du r| j                  du ry| j                         t        j                  | j
                  <   y)z
        Saves the token dict in the specified environmental variable
        :param bool force: Force save even when state has not changed
        :return bool: Success / Failure
        FT)r-   r(   r   r   r   r   r   s     r   r   zEnvTokenBackend.save_token  sC     {{E>d55>*...*:

4&&'r   c                t    | j                   t        j                  v rt        j                  | j                   = yy)zb
        Deletes the token environmental variable
        :return bool: Success / Failure
        TFr   r   r   r.   s    r   r   zEnvTokenBackend.delete_token  s.    
 "**,

4../r   c                :    | j                   t        j                  v S )z
        Checks if the token exists in the environmental variables
        :return bool: True if exists, False otherwise
        r   r.   s    r   r   zEnvTokenBackend.check_token  s    
 ""bjj00r   r   r   r   r   r   s   @r   r   r     s%    :P( 1r   r   c                  L     e Zd ZdZd fd	Zd Zd	dZd
d	dZd	dZd	dZ	 xZ
S )FirestoreBackendz3A Google Firestore database backend to store tokensc                    t         |           || _        || _        || _        |j                  |      j                  |      | _        || _        y)ax  
        Init Backend
        :param firestore.Client client: the firestore Client instance
        :param str collection: the firestore collection where to store tokens (can be a field_path)
        :param str doc_id: # the key of the token document. Must be unique per-case.
        :param str field_name: the name of the field that stores the token in the document
        N)r&   r'   client
collectiondoc_iddocumentdoc_ref
field_name)r   r   r   r   r   r*   s        r   r'   zFirestoreBackend.__init__  sI     	$((4==fE$r   c                :    d| j                    d| j                   S )NzCollection: z
. Doc Id: )r   r   r.   s    r   r   zFirestoreBackend.__repr__  s    doo.jFFr   c           	     R   	 | j                   j                         }|r@|j                  r4|j                  | j                        }|r| j                  |      | _
        yy# t        $ r>}t        j	                  d| j
                   d| j                   d|        d}Y d}~d}~ww xY w)\
        Retrieves the token from the store
        :return bool: Success / Failure
        Token (collection: 
, doc_id: +) could not be retrieved from the backend: NTF)r   r5   r   rJ   r   r   r   r   r   r   r-   )r   docr   r   s       r   r   zFirestoreBackend.load_token  s    
	,,""$C 3::0I"..y9  	II%doo%6j N<<=3@ C	s   A 	B&(4B!!B&c                   | j                   sy|du r| j                  du ry	 | j                  j                  | j                  | j                         i       y# t        $ r"}t        j                  d|        Y d}~yd}~ww xY w)
        Saves the token dict in the store
        :param bool force: Force save even when state has not changed
        :return bool: Success / Failure
        FTr   N)	r-   r(   r   setr   r   r   rJ   r   r   r   r   s      r   r   zFirestoreBackend.save_token  sz     {{E>d55>	LLdoot~~/?@A
 	  	II21#67	s   5A 	B!A>>Bc                    	 | j                   j                          y# t        $ r/}t        j	                  d| j
                   d|        Y d}~yd}~ww xY w)Z
        Deletes the token from the store
        :return bool: Success / Failure
        z!Could not delete the token (key: z): NFT)r   deleter   rJ   r   r   )r   r   s     r   r   zFirestoreBackend.delete_token'  sS    
	LL!   	II3DKK=A3G 		s    	A%AAc           	         	 | j                   j                         }|xr |j                  S # t        $ r>}t        j	                  d| j
                   d| j                   d|        d}Y d}~Rd}~ww xY w)a
        Checks if the token exists
        :return bool: True if it exists on the store
        r   r   r   N)r   r5   r   rJ   r   r   r   r   )r   r   r   s      r   r   zFirestoreBackend.check_token5  sv    
	,,""$C !szz!  	II%doo%6 7KK= KA3P C	s   , 	A34A..A3rb   r   r   r   r   s   @r   r   r     s%    =%(G(*"r   r   c                  J     e Zd ZdZ fdZd ZddZd	ddZddZddZ	 xZ
S )
AWSS3Backendz!An AWS S3 backend to store tokensc                    	 ddl }t        |           || _        || _        |j                  d      | _        y# t        $ r}t        d      |d}~ww xY w)z
        Init Backend
        :param str bucket_name: Name of the S3 bucket
        :param str filename: Name of the S3 file
        r   N;Please install the boto3 package to use this token backend.s3)	boto3ModuleNotFoundErrorr   r&   r'   bucket_namefilenamer   _client)r   r   r   r   r   r*   s        r   r'   zAWSS3Backend.__init__H  s\    	
 	& ||D) # 	M	s   : 	AAAc                <    d| j                    d| j                   dS )NzAWSS3Backend('', ''))r   r   r.   s    r   r   zAWSS3Backend.__repr__[  s"     0 01dmm_BGGr   c                ,   	 | j                   j                  | j                  | j                        }| j	                  |d   j                               | _        y# t        $ r/}t        j                  d| j                   d|        Y d}~yd}~ww xY w)z]
        Retrieves the token from the store
         :return bool: Success / Failure
        BucketKeyBodyzToken (r   NFT)
r   
get_objectr   r   r   r   r-   r   rJ   r   )r   token_objectr   s      r   r   zAWSS3Backend.load_token^  s    
		<<22''T]] 3 L **<+?+D+D+FGDK   	II$--(STUSVW 		s   AA 	B$%BBc                4   | j                   sy|du r| j                  du ryt        j                  | j	                               }| j                         r4	 | j                  j                  | j                  | j                  |      }y	 | j                  j                  d| j                  | j                  |d      }y# t        $ r"}t        j                  d|        Y d}~yd}~ww xY w# t        $ r"}t        j                  d	|        Y d}~yd}~ww xY w)
r   FT)r   r   r   zToken file could not be saved: Nprivatez
text/plain)ACLr   r   r   ContentTypez!Token file could not be created: )r-   r(   r   encoder   r   r   
put_objectr   r   r   rJ   r   )r   r   r   _r   r   s         r   r   zAWSS3Backend.save_tokeno  s    {{E>d55>JJt~~/0	LL++++Y , & 
LL++!++" , ,  !  		;A3?@  		=aSABs0   2B> 	4C, >	C)C$$C),	D5DDc                $   	 | j                   j                  | j                  | j                        }t        j                  d| j                   d| j                   d       y# t        $ r"}t        j                  d|        Y d}~yd}~ww xY w)	r   r   zDeleted token file z in bucket .Tz!Token file could not be deleted: NF)r   delete_objectr   r   rJ   warningr   r   r   r   r   s      r   r   zAWSS3Backend.delete_token  s    
		**$2B2B*VA
 KK%dmm_K@P@P?QQRS   	II9!=>	s   1A$ $	B-B

Bc                v    	 | j                   j                  | j                  | j                        }y#  Y yxY w)r   r   TF)r   head_objectr   r   r   r  s     r   r   zAWSS3Backend.check_token  s9    
	((0@0@dmm(TA 	s   14 8r   r   r   r   s   @r   r   r   E  s&    +*&H""H 
r   r   c                  J     e Zd ZdZ fdZd ZddZd	ddZddZddZ	 xZ
S )
AWSSecretsBackendz.An AWS Secrets Manager backend to store tokensc                    	 ddl }t        |           || _        || _        |j                  d|      | _        y# t        $ r}t        d      |d}~ww xY w)z
        Init Backend
        :param str secret_name: Name of the secret stored in Secrets Manager
        :param str region_name: AWS region hosting the secret (for example, 'us-east-2')
        r   Nr   secretsmanager)region_name)	r   r   r   r&   r'   secret_namer  r   r   )r   r  r  r   r   r*   s        r   r'   zAWSSecretsBackend.__init__  sb    	
 	&&||$4+|N # 	M	s   < 	AAAc                <    d| j                    d| j                   dS )NzAWSSecretsBackend('r   r   )r  r  r.   s    r   r   zAWSSecretsBackend.__repr__  s%    $T%5%5$6d4;K;K:LBOOr   c                    	 | j                   j                  | j                        }|d   }| j                  |      | _        y# t
        $ r/}t        j                  d| j                   d|        Y d}~yd}~ww xY w)r   SecretIdSecretStringzToken (secret: r   NFT)r   get_secret_valuer  r   r-   r   rJ   r   )r   get_secret_value_responser   r   s       r   r   zAWSSecretsBackend.load_token  s    

	(,(E(E)) )F )% 2.AI**95DK   	II!$"2"2!33^_`^ab 		s   AA 	A<%A77A<c                <   | j                   sy|du r| j                  du ry| j                         r7	 | j                  j	                  | j
                  | j                               }y	 | j                  j                  | j
                  d| j                               }t        j                  d|d	    d
|d    d       y# t        $ r"}t        j                  d|        Y d}~yd}~ww xY w# t        $ r"}t        j                  d|        Y d}~yd}~ww xY w)r   FT)r  r  z!Token secret could not be saved: NzLToken generated by the O365 python package (https://pypi.org/project/O365/).)NameDescriptionr  z
Created secret r   (ARNz). Note: using AWS Secrets Manager incurs charges, please see https://aws.amazon.com/secrets-manager/pricing/ for pricing details.
z#Token secret could not be created: )r-   r(   r   r   update_secretr  r   r   rJ   r   create_secretr  )r   r   r  r   r   s        r   r   zAWSSecretsBackend.save_token  s    {{E>d55>LL..!--DNN<L / , LL..)) n!%!1 /  '&	{"QuXJ ?h i
 '  		=aSAB  		?sCDs/   5C )6C0 	C-C((C-0	D9DDc                    	 | j                   j                  | j                  d      }t        j	                  d|d    d|d    d       y# t
        $ r"}t        j                  d|        Y d	}~y
d	}~ww xY w)r   T)r  ForceDeleteWithoutRecoveryzDeleted token secret r  r!  r"  z).z#Token secret could not be deleted: NF)r   delete_secretr  rJ   r  r   r   r  s      r   r   zAWSSecretsBackend.delete_token  s}    
		**))d + A KK/&	{"QuXJbIJ  	II;A3?@	s   'A 	A7A22A7c                `    	 | j                   j                  | j                        }y#  Y yxY w)r   r  TF)r   describe_secretr  r  s     r   r   zAWSSecretsBackend.check_token  s3    
	,,d6F6F,GA 	s   &) -r   r   r   r   s   @r   r  r    s'    8O&P&$L 
r   r  c                  <     e Zd ZdZd fdZd ZddZdddZ xZS )	BitwardenSecretsManagerBackendz3A Bitwarden Secrets Manager backend to store tokensc                    	 ddl m} t        |            |       | _        | j                  j                         j                  |       || _	        d| _
        y# t        $ r}t        d      |d}~ww xY w)z
        Init Backend
        :param str access_token: Access Token used to access the Bitwarden Secrets Manager API
        :param str secret_id: ID of Bitwarden Secret used to store the O365 token
        r   )BitwardenClientzCPlease install the bitwarden-sdk package to use this token backend.N)bitwarden_sdkr-  r   r   r&   r'   r   authlogin_access_token	secret_idsecret)r   r:   r1  r-  r   r*   s        r   r'   z'BitwardenSecretsManagerBackend.__init__"  sp    	5
 	%'--l;" # 	U	s   A 	A5$A00A5c                "    d| j                    dS )Nz BitwardenSecretsManagerBackend('r   )r1  r.   s    r   r   z'BitwardenSecretsManagerBackend.__repr__8  s    1$..1ADDr   c                4   | j                   j                         j                  | j                        }|j                  sy|j
                  | _        	 | j                  | j                  j                        | _	        y#  t        j                  d       Y yxY w)zl
        Retrieves the token from Bitwarden Secrets Manager
        :return bool: Success / Failure
        FTz#Existing token could not be decoded)r   secretsr5   r1  successr   r2  r   valuer-   loggingr  )r   resps     r   r   z)BitwardenSecretsManagerBackend.load_token;  su    
 {{""$((8||ii	**4;;+<+<=DK	OOABs   *A> >Bc                   | j                   t        d      | j                  sy|du r| j                  du ry| j                  j                         j                  | j                   j                  | j                   j                  | j                   j                  | j                   j                  | j                         | j                   j                  g       y)z
        Saves the token dict in Bitwarden Secrets Manager
        :param bool force: Force save even when state has not changed
        :return bool: Success / Failure
        z)You have to set "self.secret" data first.FT)r2  rQ   r-   r(   r   r5  updateidkeynoteorganization_idr   
project_idr   s     r   r   z)BitwardenSecretsManagerBackend.save_tokenM  s     ;;HII{{E>d55>$$KKNNKKOOKKKK''NN[[##$	
 r   )r:   r   r1  r   r   r   )	r   r    r!   r"   r'   r   r   r   r   r   s   @r   r+  r+    s     =,E$ r   r+  c                  L     e Zd ZdZd fd	Zd Zd	dZd
d	dZd	dZd	dZ	 xZ
S )DjangoTokenBackenda  
    A Django database token backend to store tokens. To use this backend add the `TokenModel`
    model below into your Django application.

    .. code-block:: python

        class TokenModel(models.Model):
            token = models.JSONField()
            created_at = models.DateTimeField(auto_now_add=True)
            updated_at = models.DateTimeField(auto_now=True)

            def __str__(self):
                return f"Token for {self.token.get('client_id', 'unknown')}"

    Example usage:

    .. code-block:: python

        from O365.utils import DjangoTokenBackend
        from models import TokenModel

        token_backend = DjangoTokenBackend(token_model=TokenModel)
        account = Account(credentials, token_backend=token_backend)
    c                0    t         |           || _        y)z
        Initializes the DjangoTokenBackend.

        :param token_model: The Django model class to use for storing and retrieving tokens (defaults to TokenModel).
        N)r&   r'   token_model)r   rD  r*   s     r   r'   zDjangoTokenBackend.__init__  s     	 'r   c                     y)NrB  r   r.   s    r   r   zDjangoTokenBackend.__repr__  r   r   c                    	 | j                   j                  j                  d      }| j                  |j                        | _        y# t        $ r"}t        j                  d|        Y d}~yd}~ww xY w)zm
        Retrieves the latest token from the Django database
        :return bool: Success / Failure
        
created_atz4No token found in the database, creating a new one: NFT)	rD  objectslatestr   rb   r-   r   rJ   r  r   token_recordr   s      r   r   zDjangoTokenBackend.load_token  si    	++33::<HL**<+=+=>DK
 	  	KKNqcRS	s   AA 	A3A..A3c                
   | j                   sy|du r| j                  du ry	 | j                  j                  j	                  | j                                y# t        $ r"}t        j                  d|        Y d}~yd}~ww xY w)z
        Saves the token dict in the Django database
        :param bool force: Force save even when state has not changed
        :return bool: Success / Failure
        FTr   r   N)	r-   r(   rD  rH  creater   r   rJ   r   r   s      r   r   zDjangoTokenBackend.save_token  s|     {{E>d55>	$$++$..2B+C
 	  	II21#67	s   4A 	B A==Bc                    	 | j                   j                  j                  d      }|j                          y# t        $ r"}t
        j                  d|        Y d}~yd}~ww xY w)zk
        Deletes the latest token from the Django database
        :return bool: Success / Failure
        rG  zCould not delete token: NFT)rD  rH  rI  r   r   rJ   r   rJ  s      r   r   zDjangoTokenBackend.delete_token  s]    
	++33::<HL!   	II045	s   58 	A#AA#c                J    | j                   j                  j                         S )z|
        Checks if any token exists in the Django database
        :return bool: True if it exists, False otherwise
        )rD  rH  r   r.   s    r   r   zDjangoTokenBackend.check_token  s    
 ''..00r   r   r   r   r   r   s   @r   rB  rB  g  s&    2	'$ *1r   rB  ) 
__future__r   r8   r7   r   r8  r   pathlibr   typingr   r   r   r   msal.token_cacher	   O365.connectionr
   	getLoggerr   rJ   ra   r   r$   r   r   r   r   r   r  r+  rB  r   r   r   <module>rV     s    "    	  ; ; '*g! :/h /hz hV	P(- P(f
) 
91& 91x^"' ^"Bh# hVl( l^E%5 EP`1) `1r   