
    @                        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mZ ddlmZ ddl	m
Z
 dZ ej                  e      Zi Z ej                          Z G d de      Z G d	 d
e      Zd Z ej,                  d      	 dd       Z ej,                  d      	 dd       Z ej,                  d      	 dd       Z ej,                  d      dd       Z ej,                  d      dd       Z G d de      Zy)a  Multi-credential file store with lock support.

This module implements a JSON credential store where multiple
credentials can be stored in one file. That file supports locking
both in a single process and across processes.

The credential themselves are keyed off of:

* client_id
* user_agent
* scope

The format of the stored data is like so::

    {
      'file_version': 1,
      'data': [
          {
              'key': {
                  'clientId': '<client id>',
                  'userAgent': '<user agent>',
                  'scope': '<scope>'
              },
              'credential': {
                  # JSON serialized Credentials.
              }
          }
      ]
    }

    N)client)util)locked_filezjbeda@google.com (Joe Beda)c                       e Zd ZdZy)ErrorzBase error for this module.N__name__
__module____qualname____doc__     7lib/third_party/oauth2client/contrib/multistore_file.pyr   r   B   s    %r   r   c                       e Zd ZdZy)NewerCredentialStoreErrorz7The credential store is a newer version than supported.Nr   r   r   r   r   r   F   s    Ar   r   c                 F    t        t        | j                                     S )al  Converts a dictionary to a tuple that can be used as an immutable key.

    The resulting key is always sorted so that logically equivalent
    dictionaries always produce an identical tuple for a key.

    Args:
        dictionary: the dictionary to use as the key.

    Returns:
        A tuple representing the dictionary in it's naturally sorted ordering.
    )tuplesorteditems)
dictionarys    r   _dict_to_tuple_keyr   J   s     
((*+,,r      c                 P    ||t        j                  |      d}t        | ||      S )a  Get a Storage instance for a credential.

    Args:
        filename: The JSON file storing a set of credentials
        client_id: The client_id for the credential
        user_agent: The user agent for the credential
        scope: string or iterable of strings, Scope(s) being requested
        warn_on_readonly: if True, log a warning if the store is readonly

    Returns:
        An object derived from client.Storage for getting/setting the
        credential.
    )clientId	userAgentscopewarn_on_readonly)r   scopes_to_string!get_credential_storage_custom_key)filename	client_id
user_agentr   r   keys         r   get_credential_storager%   Y   s3    " !z))%02C,#(8: :r      c                 &    d|i}t        | ||      S )a  Get a Storage instance for a credential using a single string as a key.

    Allows you to provide a string as a custom key that will be used for
    credential storage and retrieval.

    Args:
        filename: The JSON file storing a set of credentials
        key_string: A string to use as the key for storing this credential.
        warn_on_readonly: if True, log a warning if the store is readonly

    Returns:
        An object derived from client.Storage for getting/setting the
        credential.
    r$   r   )r    )r!   
key_stringr   key_dicts       r   (get_credential_storage_custom_string_keyr*   p   s#    $ z"H,(-=? ?r   c                 T    t        | |      }t        |      }|j                  |      S )a  Get a Storage instance for a credential using a dictionary as a key.

    Allows you to provide a dictionary as a custom key that will be used for
    credential storage and retrieval.

    Args:
        filename: The JSON file storing a set of credentials
        key_dict: A dictionary to use as the key for storing this credential.
                  There is no ordering of the keys in the dictionary. Logically
                  equivalent dictionaries will produce equivalent storage keys.
        warn_on_readonly: if True, log a warning if the store is readonly

    Returns:
        An object derived from client.Storage for getting/setting the
        credential.
    r   )_get_multistorer   _get_storage)r!   r)   r   
multistorer$   s        r   r    r       s,    & !<LMJ
X
&C""3''r      c                     t        | |      }|j                          	 |j                         |j                          S # |j                          w xY w)a  Gets all the registered credential keys in the given Multistore.

    Args:
        filename: The JSON file storing a set of credentials
        warn_on_readonly: if True, log a warning if the store is readonly

    Returns:
        A list of the credential keys present in the file.  They are returned
        as dictionaries that can be passed into
        get_credential_storage_custom_key to get the actual credentials.
    r   )r,   _lock_get_all_credential_keys_unlockr!   r   r.   s      r   get_all_credential_keysr5      sG     !<LMJ224
s	   ? Ac                 
   t         j                  j                  |       } t        j	                          	 t
        j                  | t        | |            }t        j                          |S # t        j                          w xY w)a  A helper method to initialize the multistore with proper locking.

    Args:
        filename: The JSON file storing a set of credentials
        warn_on_readonly: if True, log a warning if the store is readonly

    Returns:
        A multistore object
    r   )	ospath
expanduser_multistores_lockacquire_multistores
setdefault_MultiStorereleaser4   s      r   r,   r,      sk     ww!!(+H$!,,k(=MNP
 	!!# 	!!#s   !A, ,Bc                       e Zd ZdZ ej
                  d      dd       Z G d dej                        Z	d Z
d Zd Zd	 Zd
 Zd Zd Zd Zd Zd Zd Zd Zd Zy)r>   z-A file backed store for multiple credentials.r&   c                     t        j                  |dd      | _        t        j                         | _        d| _        || _        | j                          d| _	        y)zOInitialize the class.

        This will create the file if necessary.
        zr+rFN)
r   
LockedFile_file	threadingLock_thread_lock
_read_only_warn_on_readonly_create_file_if_needed_data)selfr!   r   s      r   __init__z_MultiStore.__init__   sM     !++HdC@
%NN,!1##% 
r   c                   4    e Zd ZdZd Zd Zd Zd Zd Zd Z	y)	_MultiStore._Storagez9A Storage object that can read/write a single credential.c                      || _         || _        y )N)_multistore_key)rL   r.   r$   s      r   rM   z_MultiStore._Storage.__init__   s    )DDIr   c                 8    | j                   j                          y)ziAcquires any lock necessary to access this Storage.

            This lock is not reentrant.
            N)rQ   r1   rL   s    r   acquire_lockz!_MultiStore._Storage.acquire_lock   s    
 ""$r   c                 8    | j                   j                          y)zRelease the Storage lock.

            Trying to release a lock that isn't held will result in a
            RuntimeError.
            N)rQ   r3   rT   s    r   release_lockz!_MultiStore._Storage.release_lock   s     $$&r   c                 v    | j                   j                  | j                        }|r|j                  |        |S )zRetrieve credential.

            The Storage lock must be held when this is called.

            Returns:
                oauth2client.client.Credentials
            )rQ   _get_credentialrR   	set_store)rL   
credentials     r   
locked_getz_MultiStore._Storage.locked_get   s5     ))99$))DJ$$T*r   c                 P    | j                   j                  | j                  |       y)zWrite a credential.

            The Storage lock must be held when this is called.

            Args:
                credentials: Credentials, the credentials to store.
            N)rQ   _update_credentialrR   )rL   credentialss     r   
locked_putz_MultiStore._Storage.locked_put  s     //		;Gr   c                 N    | j                   j                  | j                         y)zDelete a credential.

            The Storage lock must be held when this is called.

            Args:
                credentials: Credentials, the credentials to store.
            N)rQ   _delete_credentialrR   rT   s    r   locked_deletez"_MultiStore._Storage.locked_delete  s     //		:r   N)
r	   r
   r   r   rM   rU   rW   r\   r`   rc   r   r   r   _StoragerO      s$    G		%	'		H	;r   rd   c                 b   t         j                  j                  | j                  j	                               s^t        j
                  d      }	 t        | j                  j	                         d      j                          t        j
                  |       yy# t        j
                  |       w xY w)zCreate an empty file if necessary.

        This method will not initialize the file. Instead it implements a
        simple version of "touch" to ensure the file has been created.
           za+bN)r7   r8   existsrD   r!   umaskopenclose)rL   	old_umasks     r   rJ   z"_MultiStore._create_file_if_needed  st     ww~~djj1134I$TZZ((*E288:# 5
 #s   2B B.c                    | j                   j                          	 | j                  j                          | j                  j                         sAd| _        | j                  r.t        j                  d| j                  j!                                t"        j$                  j'                  | j                  j!                               dk(  r-t        j)                  d	       i | _        | j-                          y| j                  r| j*                  | j/                          yy# t        t
        f$ r}|j                  t        j                  k(  rt        j                  d       n|j                  t        j                  k(  rt        j                  d       ng|j                  t        j                  k(  rt        j                  d       n4|j                  t        j                  k(  rt        j                  d       n Y d}~d}~ww xY w)
zLock the entire multistore.z:File system does not support locking the credentials file.zVFile system is out of resources for writing the credentials file (is your disk full?).z>Lock contention on multistore file, opening in read-only mode.zCannot access credentials file.NTzThe credentials file (%s) is not writable. Opening in read-only mode. Any refreshed credentials will only be valid for this run.r   z"Initializing empty multistore file)rG   r;   rD   open_and_lockIOErrorOSErrorerrnoENOSYSloggerwarnENOLCKEDEADLKEACCES	is_lockedrH   rI   r!   r7   r8   getsizedebugrK   _write_refresh_data_cache)rL   es     r   r1   z_MultiStore._lock&  sp   !!#	JJ$$& zz##%"DO%% 2 48::3F3F3HJ
 77??4::..01Q6LL=>DJKKMDJJ$6 $$& %77 ! 	ww%,,& 0 1ELL( E FEMM) 1 2ELL(=>	s   D" "H	1CHH	c                 l    | j                   j                          | j                  j                          y)z#Release the lock on the multistore.N)rD   unlock_and_closerG   r?   rT   s    r   r3   z_MultiStore._unlockN  s$    

##%!!#r   c                     | j                   j                         sJ | j                  j                         j	                  d       t        j                  | j                  j                               S )zGet the raw content of the multistore file.

        The multistore must be locked when this is called.

        Returns:
            The contents of the multistore decoded as JSON.
        r   )rG   lockedrD   file_handleseekjsonloadrT   s    r   _locked_json_readz_MultiStore._locked_json_readS  sS       '')))

 %%a(yy//122r   c                 \   | j                   j                         sJ | j                  ry| j                  j	                         j                  d       t        j                  || j                  j	                         ddd       | j                  j	                         j                          y)zWrite a JSON serializable data structure to the multistore.

        The multistore must be locked when this is called.

        Args:
            data: The data to be serialized and written.
        Nr   Tr&   ),z: )	sort_keysindent
separators)	rG   r   rH   rD   r   r   r   dumptruncate)rL   datas     r   _locked_json_writez_MultiStore._locked_json_write_  s       '')))??

 %%a(		$

..0 {	D

 ))+r   c                    i | _         	 | j                         }d}	 |d   }|dkD  rt        dj                  |            g }	 |d   }|D ]&  }	 | j                  |      \  }}|| j                   |<   ( y# t        $ r t        j	                  d       Y yw xY w# t        $ r t        j	                  d       Y w xY w# t        t        f$ r Y w xY w#  t        j                  d	d
       Y xY w)zRefresh the contents of the multistore.

        The multistore must be locked when this is called.

        Raises:
            NewerCredentialStoreError: Raised when a newer client has written
            the store.
        zECredential data store could not be loaded. Will ignore and overwrite.Nr   file_versionz\Missing version for credential data store. It may be corrupt or an old version. Overwriting.r/   zMCredential file has file_version of {0}. Only file_version of 1 is supported.r   z#Error decoding credential, skippingT)exc_info)rK   r   	Exceptionrr   rs   r   format	TypeErrorKeyError_decode_credential_from_jsoninfo)rL   raw_dataversionr_   
cred_entryr$   r[   s          r   r{   z_MultiStore._refresh_data_cacheo  s"    
	--/H 	C~.G Q;+77=vgH H 	"6*K &J+"&"C"CJ"OZ",

3 &-  	KK 5 6	  	CKK B C	C 8$ 		+A%)  +s@   A4 B B< #C4BBB98B9<CCC,c                     |d   }t        |      }d}t        j                  j                  t	        j
                  |d               }||fS )a  Load a credential from our JSON serialization.

        Args:
            cred_entry: A dict entry from the data member of our format

        Returns:
            (key, cred) where the key is the key tuple and the cred is the
            OAuth2Credential object.
        r$   Nr[   )r   r   Credentialsnew_from_jsonr   dumps)rL   r   raw_keyr$   r[   s        r   r   z(_MultiStore._decode_credential_from_json  sO     U# )
''55JJz,/02
Z  r   c                    ddi}g }||d<   | j                   j                         D ]G  \  }}t        |      }t        j                  |j                               }|j                  ||d       I | j                  |       y)zPWrite the cached data back out.

        The multistore must be locked.
        r   r/   r   )r$   r[   N)rK   r   dictr   loadsto_jsonappendr   )rL   r   	raw_credscred_keycredr   raw_creds          r   rz   z_MultiStore._write  sy    
 #A&	$ $

 0 0 2Xt8nGzz$,,.1HWHEF !3 	)r   c                 n    | j                   j                         D cg c]  }t        |       c}S c c}w )zGets all the registered credential keys in the multistore.

        Returns:
            A list of dictionaries corresponding to all the keys currently
            registered
        )rK   keysr   rL   r$   s     r   r2   z$_MultiStore._get_all_credential_keys  s-     &*ZZ__%67%6cS	%6777s   2c                 :    | j                   j                  |d      S )zGet a credential from the multistore.

        The multistore must be locked.

        Args:
            key: The key used to retrieve the credential

        Returns:
            The credential specified or None if not present
        N)rK   getr   s     r   rY   z_MultiStore._get_credential  s     zz~~c4((r   c                 B    || j                   |<   | j                          y)zUpdate a credential and write the multistore.

        This must be called when the multistore is locked.

        Args:
            key: The key used to retrieve the credential
            cred: The OAuth2Credential to update/set
        N)rK   rz   )rL   r$   r   s      r   r^   z_MultiStore._update_credential  s     

3r   c                 ^    	 | j                   |= | j                          y# t        $ r Y w xY w)zDelete a credential and write the multistore.

        This must be called when the multistore is locked.

        Args:
            key: The key used to retrieve the credential
        N)rK   r   rz   r   s     r   rb   z_MultiStore._delete_credential  s1    	

3 	  		s     	,,c                 &    | j                  | |      S )a
  Get a Storage object to get/set a credential.

        This Storage is a 'view' into the multistore.

        Args:
            key: The key used to retrieve the credential

        Returns:
            A Storage object that can be used to get/set this cred
        )rd   r   s     r   r-   z_MultiStore._get_storage  s     }}T3''r   NT)r	   r
   r   r   r   
positionalrM   r   Storagerd   rJ   r1   r3   r   r   r{   r   rz   r2   rY   r^   rb   r-   r   r   r   r>   r>      sv    7T__Q *5;6>> 5;n$&'P$

3, )+V!"*8)
(r   r>   r   )r   rp   r   loggingr7   rE   oauth2clientr   r   oauth2client.contribr   
__author__	getLoggerr	   rr   r<   rF   r:   r   r   r   r   r   r%   r*   r    r5   r,   objectr>   r   r   r   <module>r      s#  @    	    ,*
			8	$ "INN$ &I &B B- ,0: :, >B? ?, 7;( (.  (  (k(& k(r   