o
    i6                  	   @   sT  d 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zddlmZ W n e	y1   ddl
mZ Y nw zejZW n eyJ   edefddiZY nw eeZdd Zd	d
 ZG dd deZG dd deZG dd deZG dd deZdd ZG dd deZdd ZG dd deZG dd deZG dd deZG dd  d eZdS )!aP  A generic persistence layer, optionally encrypted on Windows, OSX, and Linux.

Should a certain encryption is unavailable, exception will be raised at run-time,
rather than at import time.

By successfully creating and using a certain persistence object,
app developer would naturally know whether the data are protected by encryption.
    N)PathABC	__slots__ c              
   C   sx   | sdS t jdkrtj| dd dS zt|  W dS  ty; } z|jtjkr/tj| r/n W Y d}~dS d}~ww )zCreates a directory, and any necessary parents.

    If the path provided is an existing file, this function raises an exception.
    :param path: The directory name that should be created.
    N)      T)exist_ok)	sysversion_infoosmakedirsOSErrorerrnoEEXISTpathisdir)r   expr   r   R/home/app/Keep/.python/lib/python3.10/site-packages/msal_extensions/persistence.py_mkdir_p   s   
r   c                 C   s   t | d S )Nzutf-8)hashlibsha256encode	hexdigest)Zinput_stringr   r   r   
_auto_hash6   s   r   c                       "   e Zd ZdZd fdd	Z  ZS )PersistenceErrorz#The base exception for persistence.Nc                    s   t t| ||| d S N)superr   __init__selferr_nomessagelocation	__class__r   r   r   C   s   zPersistenceError.__init__NNN__name__
__module____qualname____doc__r   __classcell__r   r   r$   r   r   =   s    r   c                       r   )PersistenceNotFoundzZThis happens when attempting BasePersistence.load() on a non-existent persistence instanceNc                    s    t t| jtj|p
d|d d S )NzPersistence not foundr!   r"   r#   )r   r-   r   r   ENOENTr   r$   r   r   r   I   s
   

zPersistenceNotFound.__init__r&   r'   r   r   r$   r   r-   G   s    r-   c                   @      e Zd ZdZdS )PersistenceEncryptionErrorz*This could be raised by persistence.save()Nr(   r)   r*   r+   r   r   r   r   r1   O       r1   c                   @   r0   )PersistenceDecryptionErrorz*This could be raised by persistence.load()Nr2   r   r   r   r   r4   R   r3   r4   c                 C   sL   t jdr
t| S t jdrt| S t jdrt| S tdt j)zBuild a suitable encrypted persistence instance based your current OS.

    If you do not need encryption, then simply use ``FilePersistence`` constructor.
    windarwinlinuxzUnsupported platform: {})r	   platform
startswith!FilePersistenceWithDataProtectionKeychainPersistenceLibsecretPersistenceRuntimeErrorformatr#   r   r   r   build_encrypted_persistenceV   s   r@   c                   @   sL   e Zd ZdZdZejdd Zejdd Zejdd Z	ejd	d
 Z
dS )BasePersistencezDAn abstract persistence defining the common interface of this familyFc                 C      t )&Save the content into this persistenceNotImplementedErrorr    contentr   r   r   savek   s   zBasePersistence.savec                 C   rB   )zuLoad content from this persistence.

        Could raise PersistenceNotFound if no save() was called before.
        rD   r    r   r   r   loadq   s   zBasePersistence.loadc                 C   rB   )zGet the last time when this persistence has been modified.

        Could raise PersistenceNotFound if no save() was called before.
        rD   rI   r   r   r   time_last_modifiedz   s   z"BasePersistence.time_last_modifiedc                 C   rB   )zBReturn the file path which this persistence stores (meta)data intorD   rI   r   r   r   get_location   s   zBasePersistence.get_locationN)r(   r)   r*   r+   is_encryptedabcabstractmethodrH   rJ   rK   rL   r   r   r   r   rA   f   s    


rA   c                 C   s   t | t jt jB t jB dS )Ni  )r   openO_RDWRO_CREATO_TRUNCr?   r   r   r   _open   s   rT   c                   @   s@   e Zd ZdZdd Zdd Zdd Zdd	 Zd
d Zdd Z	dS )FilePersistencez8A generic persistence, storing data in a plain-text filec                 C   s0   |st dtj|| _ttj| j d S )NzRequires a file path)
ValueErrorr   r   
expanduser	_locationr   dirname)r    r#   r   r   r   r      s   zFilePersistence.__init__c                 C   sB   t t| jd}|| W d   dS 1 sw   Y  dS )rC   zw+N)r   fdopenrT   rX   write)r    rG   handler   r   r   rH      s   "zFilePersistence.savec              
   C   sr   zt | jd}| W  d   W S 1 sw   Y  W dS  ty8 } z|jtjkr3td| jd d}~ww )z"Load content from this persistencerNGPersistence not initialized. You can recover by calling a save() first.r"   r#   )rP   rX   readEnvironmentErrorr   r/   r-   )r    r\   r   r   r   r   rJ      s   (zFilePersistence.loadc              
   C   sF   zt j| jW S  ty" } z|jtjkrtd| jd d }~ww )Nr^   r_   )r   r   getmtimerX   ra   r   r/   r-   )r    r   r   r   r   rK      s   z"FilePersistence.time_last_modifiedc                 C   s   t | j  dS )zDTo touch this file-based persistence without writing content into itN)r   rX   touchrI   r   r   r   rc      s   zFilePersistence.touchc                 C   s   | j S r   )rX   rI   r   r   r   rL      s   zFilePersistence.get_locationN)
r(   r)   r*   r+   r   rH   rJ   rK   rc   rL   r   r   r   r   rU      s    rU   c                       s6   e Zd ZdZdZd
 fdd	Zdd Zdd	 Z  ZS )r:   zcA generic persistence with data stored in a file,
    protected by Win32 encryption APIs on WindowsT c                    s,   ddl m} ||d| _tt| | dS )z7Initialization could fail due to unsatisfied dependency   )WindowsDataProtectionAgent)entropyN)windowsrf   	_dp_agentr   r:   r   )r    r#   rg   rf   r$   r   r   r      s   z*FilePersistenceWithDataProtection.__init__c              
   C   s   z| j |}W n ty! } ztt|dd d|dd }~ww tt| j	d}|
| W d    d S 1 s<w   Y  d S )Nwinerrorz2Encryption failed: {} Consider disable encryption.)r!   r"   zwb+)ri   Zprotectr   r1   getattrr>   r   rZ   rT   rX   r[   )r    rG   data	exceptionr\   r   r   r   rH      s   
"z&FilePersistenceWithDataProtection.savec              
   C   s   zt | jd}| }W d    n1 sw   Y  W n ty; } z|jtjkr1td| jdtd  d }~ww z| j	
|W S  ty^ } ztt|dd d|| jdd }~ww )Nrbr^   r_   zDPAPI error likely caused by file content not previously encrypted. App developer should migrate by calling save(plaintext) first.rj   zDecryption failed: {} App developer may consider this guidance: https://github.com/AzureAD/microsoft-authentication-extensions-for-python/wiki/PersistenceDecryptionErrorr.   )rP   rX   r`   ra   r   r/   r-   loggerrm   ri   Z	unprotectr   r4   rk   r>   )r    r\   rl   r   rm   r   r   r   rJ      s8   

z&FilePersistenceWithDataProtection.load)rd   )	r(   r)   r*   r+   rM   r   rH   rJ   r,   r   r   r$   r   r:      s    r:   c                   @   >   e Zd ZdZdZdddZdd Zdd	 Zd
d Zdd Z	dS )r;   z`A generic persistence with data stored in,
    and protected by native Keychain libraries on OSXTNc                 C   sF   ddl m}m} t|| _|| _|| _d}|p|| _|pt|| _	dS )zInitialization could fail due to unsatisfied dependency.

        :param signal_location: See :func:`persistence.LibsecretPersistence.__init__`
        re   )KeychainKeychainErrorzmsal-extensionsN)
Zosxrq   rr   rU   _file_persistence	_Keychain_KeychainError_service_namer   _account_name)r    signal_locationZservice_nameZaccount_namerq   rr   Zdefault_service_namer   r   r   r      s   

zKeychainPersistence.__init__c                 C   sH   |   }|| j| j| W d    n1 sw   Y  | j  d S r   )rt   Zset_generic_passwordrv   rw   rs   rc   )r    rG   lockerr   r   r   rH   
  s   

zKeychainPersistence.savec                 C   s   |   3}z|| j| jW W  d    S  | jy6 } z|j| jjkr1td| j| jdd d }~ww 1 s:w   Y  d S )NzService:{} Account:{}zMKeychain persistence not initialized. You can recover by call a save() first.)r#   r"   )	rt   Zget_generic_passwordrv   rw   ru   Zexit_statusZITEM_NOT_FOUNDr-   r>   )r    ry   exr   r   r   rJ     s$   
zKeychainPersistence.loadc                 C   
   | j  S r   rs   rK   rI   r   r   r   rK   "     
z&KeychainPersistence.time_last_modifiedc                 C   r{   r   rs   rL   rI   r   r   r   rL   %  r}   z KeychainPersistence.get_locationNN
r(   r)   r*   r+   rM   r   rH   rJ   rK   rL   r   r   r   r   r;      s    
r;   c                   @   rp   )r<   zcA generic persistence with data stored in,
    and protected by native libsecret libraries on LinuxTNc                 K   sD   ddl m}m} |  ||pt||pi fi || _t|| _dS )aQ  Initialization could fail due to unsatisfied dependency.

        :param string signal_location:
            Besides saving the real payload into encrypted storage,
            this class will also touch this signal file.
            Applications may listen a FileSystemWatcher.Changed event for reload.
            https://docs.microsoft.com/en-us/dotnet/api/system.io.filesystemwatcher.changed?view=netframework-4.8#remarks
        :param string schema_name: See :func:`libsecret.LibSecretAgent.__init__`
        :param dict attributes: See :func:`libsecret.LibSecretAgent.__init__`
        re   )LibSecretAgent	trial_runN)Z	libsecretr   r   r   _agentrU   rs   )r    rx   Zschema_name
attributeskwargsr   r   r   r   r   r   .  s   zLibsecretPersistence.__init__c                 C   s   | j |r| j  d S d S r   )r   rH   rs   rc   rF   r   r   r   rH   A  s   zLibsecretPersistence.savec                 C   s    | j  }|d u rtdd|S )NzLKeyring persistence not initialized. You can recover by call a save() first.)r"   )r   rJ   r-   )r    rl   r   r   r   rJ   E  s   
zLibsecretPersistence.loadc                 C   r{   r   r|   rI   r   r   r   rK   O  r}   z'LibsecretPersistence.time_last_modifiedc                 C   r{   r   r~   rI   r   r   r   rL   R  r}   z!LibsecretPersistence.get_locationr   r   r   r   r   r   r<   )  s    

r<   ) r+   rN   r   r   r   loggingr	   pathlibr   ImportErrorZpathlib2r   AttributeErrorABCMetaobject	getLoggerr(   ro   r   r   IOErrorr   r-   r1   r4   r@   rA   rT   rU   r:   r;   r<   r   r   r   r   <module>   s>    


"561