a
    ù!fŸ-  ã                   @   s¸   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ddlmZ ddl	m
Z
 ddl	mZ dZe e¡Zi Ze ¡ Zdd„ Zd	d
„ Zdd„ ZG dd„ deƒZdd„ ZG dd„ dejƒZdS )a’	  Multiprocess file credential storage.

This module provides file-based storage that supports multiple credentials and
cross-thread and process access.

This module supersedes the functionality previously found in `multistore_file`.

This module provides :class:`MultiprocessFileStorage` which:
    * Is tied to a single credential via a user-specified key. This key can be
      used to distinguish between multiple users, client ids, and/or scopes.
    * Can be safely accessed and refreshed across threads and processes.

Process & thread safety guarantees the following behavior:
    * If one thread or process refreshes a credential, subsequent refreshes
      from other processes will re-fetch the credentials from the file instead
      of performing an http request.
    * If two processes or threads attempt to refresh concurrently, only one
      will be able to acquire the lock and refresh, with the deadlock caveat
      below.
    * The interprocess lock will not deadlock, instead, the if a process can
      not acquire the interprocess lock within ``INTERPROCESS_LOCK_DEADLINE``
      it will allow refreshing the credential but will not write the updated
      credential to disk, This logic happens during every lock cycle - if the
      credentials are refreshed again it will retry locking and writing as
      normal.

Usage
=====

Before using the storage, you need to decide how you want to key the
credentials. A few common strategies include:

    * If you're storing credentials for multiple users in a single file, use
      a unique identifier for each user as the key.
    * If you're storing credentials for multiple client IDs in a single file,
      use the client ID as the key.
    * If you're storing multiple credentials for one user, use the scopes as
      the key.
    * If you have a complicated setup, use a compound key. For example, you
      can use a combination of the client ID and scopes as the key.

Create an instance of :class:`MultiprocessFileStorage` for each credential you
want to store, for example::

    filename = 'credentials'
    key = '{}-{}'.format(client_id, user_id)
    storage = MultiprocessFileStorage(filename, key)

To store the credentials::

    storage.put(credentials)

If you're going to continue to use the credentials after storing them, be sure
to call :func:`set_store`::

    credentials.set_store(storage)

To retrieve the credentials::

    storage.get(credentials)

é    N)Ú	iteritems)Ú_helpers)Úclienté   c                 C   s6   t j | ¡rdS t| dƒ ¡  t d | ¡¡ dS dS )zCreates the an empty file if it does not already exist.

    Returns:
        True if the file was created, False otherwise.
    Fza+bzCredential file {0} createdTN)ÚosÚpathÚexistsÚopenÚcloseÚloggerÚinfoÚformat©Úfilename© r   úo/var/www/html/python-backend/venv/lib/python3.9/site-packages/oauth2client/contrib/multiprocess_file_storage.pyÚ_create_file_if_neededd   s
    r   c              	   C   s¸   z|   d¡ t | ¡}W n  ty8   t d¡ i  Y S 0 | d¡dkrVt d¡ i S i }t| di ¡ƒD ]H\}}z"t 	|¡}t
j |¡}|||< W qj   t d |¡¡ Y qj0 qj|S )a$  Load credentials from the given file handle.

    The file is expected to be in this format:

        {
            "file_version": 2,
            "credentials": {
                "key": "base64 encoded json representation of credentials."
            }
        }

    This function will warn and return empty credentials instead of raising
    exceptions.

    Args:
        credentials_file: An open file handle.

    Returns:
        A dictionary mapping user-defined keys to an instance of
        :class:`oauth2client.client.Credentials`.
    r   z@Credentials file could not be loaded, will ignore and overwrite.Úfile_versioné   z=Credentials file is not version 2, will ignore and overwrite.Úcredentialsz)Invalid credential {0} in file, ignoring.)ÚseekÚjsonÚloadÚ	Exceptionr   ÚwarningÚgetr   Úbase64Ú	b64decoder   ÚCredentialsZnew_from_jsonr   )Úcredentials_fileÚdatar   ÚkeyÚencoded_credentialÚcredential_jsonÚ
credentialr   r   r   Ú_load_credentials_files   s0    
ÿ
ÿ
ÿr%   c                 C   sh   di dœ}t |ƒD ]2\}}| ¡ }t t t |¡¡¡}||d |< q|  d¡ t 	|| ¡ |  
¡  dS )a1  Writes credentials to a file.

    Refer to :func:`_load_credentials_file` for the format.

    Args:
        credentials_file: An open file handle, must be read/write.
        credentials: A dictionary mapping user-defined keys to an instance of
            :class:`oauth2client.client.Credentials`.
    r   )r   r   r   r   N)r   Úto_jsonr   Z_from_bytesr   Ú	b64encodeÚ	_to_bytesr   r   ÚdumpÚtruncate)r   r   r    r!   r$   r#   r"   r   r   r   Ú_write_credentials_file¦   s    

ÿ
r+   c                   @   sX   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d„ Z
dd„ Zdd„ ZdS )Ú_MultiprocessStorageBackenda  Thread-local backend for multiprocess storage.

    Each process has only one instance of this backend per file. All threads
    share a single instance of this backend. This ensures that all threads
    use the same thread lock and process lock when accessing the file.
    c                 C   s8   d | _ || _t d |¡¡| _t ¡ | _d| _	i | _
d S )Nz{0}.lockF)Ú_fileÚ	_filenameÚ	fastenersZInterProcessLockr   Ú_process_lockÚ	threadingÚLockÚ_thread_lockÚ
_read_onlyÚ_credentials)Úselfr   r   r   r   Ú__init__Å   s    ÿ
z$_MultiprocessStorageBackend.__init__c                 C   s.   | j s
dS t| j ƒ}| j |¡ t d¡ dS )z)(Re-)loads the credentials from the file.NzRead credential file)r-   r%   r5   Úupdater   Údebug)r6   Zloaded_credentialsr   r   r   Ú_load_credentialsÎ   s
    
z-_MultiprocessStorageBackend._load_credentialsc                 C   s8   | j rt d¡ d S t| j| jƒ t d | j¡¡ d S )Nz+In read-only mode, not writing credentials.zWrote credential file {0}.)r4   r   r9   r+   r-   r5   r   r.   ©r6   r   r   r   Ú_write_credentialsØ   s
    
z._MultiprocessStorageBackend._write_credentialsc                 C   s|   | j  ¡  | jjtd}|r<t| jƒ t| jdƒ| _d| _n4t	 
d¡ tj | j¡rdt| jdƒ| _nd | _d| _|  ¡  d S )N)Útimeoutzr+Fz¡Failed to obtain interprocess lock for credentials. If a credential is being refreshed, other processes may not see the updated access token and refresh as well.ÚrT)r3   Úacquirer0   ÚINTERPROCESS_LOCK_DEADLINEr   r.   r	   r-   r4   r   Úwarnr   r   r   r:   )r6   Úlockedr   r   r   Úacquire_lockà   s    

ÿz(_MultiprocessStorageBackend.acquire_lockc                 C   s8   | j d ur| j  ¡  d | _ | js*| j ¡  | j ¡  d S ©N)r-   r
   r4   r0   Úreleaser3   r;   r   r   r   Úrelease_lockö   s    


z(_MultiprocessStorageBackend.release_lockc                 C   s(   |d u rdS |j rdS |jr dS dS d S )NTF)ÚinvalidZaccess_token_expired©r6   r   r   r   r   Ú_refresh_predicate   s    z._MultiprocessStorageBackend._refresh_predicatec                 C   s2   | j  |d ¡}|  |¡r.|  ¡  | j  |d ¡}|S rD   )r5   r   rI   r:   ©r6   r!   r   r   r   r   Ú
locked_get
  s
    
z&_MultiprocessStorageBackend.locked_getc                 C   s   |   ¡  || j|< |  ¡  d S rD   )r:   r5   r<   rJ   r   r   r   Ú
locked_put  s    
z&_MultiprocessStorageBackend.locked_putc                 C   s"   |   ¡  | j |d ¡ |  ¡  d S rD   )r:   r5   Úpopr<   )r6   r!   r   r   r   Úlocked_delete  s    z)_MultiprocessStorageBackend.locked_deleteN)Ú__name__Ú
__module__Ú__qualname__Ú__doc__r7   r:   r<   rC   rF   rI   rK   rL   rN   r   r   r   r   r,   ½   s   	


r,   c                 C   sP   t j | ¡} t, | tvr&t| ƒt| < t|  W  d  ƒ S 1 sB0    Y  dS )a_  A helper method to get or create a backend with thread locking.

    This ensures that only one backend is used per-file per-process, so that
    thread and process locks are appropriately shared.

    Args:
        filename: The full path to the credential storage file.

    Returns:
        An instance of :class:`_MultiprocessStorageBackend`.
    N)r   r   ÚabspathÚ_backends_lockÚ	_backendsr,   r   r   r   r   Ú_get_backend$  s
    rV   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 )ÚMultiprocessFileStorageaC  Multiprocess file credential storage.

    Args:
      filename: The path to the file where credentials will be stored.
      key: An arbitrary string used to uniquely identify this set of
          credentials. For example, you may use the user's ID as the key or
          a combination of the client ID and user ID.
    c                 C   s   || _ t|ƒ| _d S rD   )Ú_keyrV   Ú_backend)r6   r   r!   r   r   r   r7   A  s    z MultiprocessFileStorage.__init__c                 C   s   | j  ¡  d S rD   )rY   rC   r;   r   r   r   rC   E  s    z$MultiprocessFileStorage.acquire_lockc                 C   s   | j  ¡  d S rD   )rY   rF   r;   r   r   r   rF   H  s    z$MultiprocessFileStorage.release_lockc                 C   s$   | j  | j¡}|dur | | ¡ |S )z›Retrieves the current credentials from the store.

        Returns:
            An instance of :class:`oauth2client.client.Credentials` or `None`.
        N)rY   rK   rX   Z	set_store)r6   r$   r   r   r   rK   K  s    
z"MultiprocessFileStorage.locked_getc                 C   s   | j  | j|¡S )z¤Writes the given credentials to the store.

        Args:
            credentials: an instance of
                :class:`oauth2client.client.Credentials`.
        )rY   rL   rX   rH   r   r   r   rL   X  s    z"MultiprocessFileStorage.locked_putc                 C   s   | j  | j¡S )z/Deletes the current credentials from the store.)rY   rN   rX   r;   r   r   r   rN   a  s    z%MultiprocessFileStorage.locked_deleteN)
rO   rP   rQ   rR   r7   rC   rF   rK   rL   rN   r   r   r   r   rW   8  s   	rW   )rR   r   r   Úloggingr   r1   r/   Úsixr   Zoauth2clientr   r   r@   Ú	getLoggerrO   r   rU   r2   rT   r   r%   r+   Úobjectr,   rV   ZStoragerW   r   r   r   r   Ú<module>   s&   ?
3g