
    @                        S r SSKrSSKrSSKrSSKrSSKrSSKJr  SSKJr  SSK	J
r
  Sr\R                  " \5      r0 r\R                   " 5       r " S S\5      r " S	 S
\5      rS r\R,                  " S5       SS j5       r\R,                  " S5       SS j5       r\R,                  " S5       SS j5       r\R,                  " S5      SS j5       r\R,                  " S5      SS j5       r " S S\5      rg)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                       \ rS rSrSrSrg)ErrorB   zBase error for this module. N__name__
__module____qualname____firstlineno____doc____static_attributes__r	       7lib/third_party/oauth2client/contrib/multistore_file.pyr   r   B   s    %r   r   c                       \ rS rSrSrSrg)NewerCredentialStoreErrorF   z7The credential store is a newer version than supported.r	   Nr
   r	   r   r   r   r   F   s    Ar   r   c                 F    [        [        U R                  5       5      5      $ )aP  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                 H    X[         R                  " U5      S.n[        XUS9$ )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   s/    " !))%02C,(8: :r      c                     SU0n[        XUS9$ )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                 L    [        XS9n[        U5      nUR                  U5      $ )au  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)    & !MJ
X
&C""3''r      c                     [        XS9nUR                  5          UR                  5       UR                  5         $ ! UR                  5         f = f)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!   )r0   _lock_get_all_credential_keys_unlockr%   r"   r2   s      r   get_all_credential_keysr9      sD     !MJ224
s	   ; Ac                    [         R                  R                  U 5      n [        R	                  5          [
        R                  U [        XS95      n[        R                  5         U$ ! [        R                  5         f = f)zA 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releaser8   s      r   r0   r0      sh     ww!!(+H$!,,k(NP
 	!!# 	!!#s   A( (A>c                       \ rS rSrSr\R                  " S5      SS j5       r " S S\R                  5      r
S rS rS	 rS
 rS rS rS rS rS rS rS rS rS rSrg)rB      z-A file backed store for multiple credentials.r*   c                     [         R                  " USS5      U l        [        R                  " 5       U l        SU l        X l        U R                  5         SU l	        g)z?Initialize 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___MultiStore.__init__   sK     !++HdC@
%NN,!1##% 
r   c                   <    \ rS rSrSrS rS rS rS rS r	S r
S	rg
)_MultiStore._Storage   z9A Storage object that can read/write a single credential.c                     Xl         X l        g )N)_multistore_key)rQ   r2   r(   s      r   rR   _MultiStore._Storage.__init__   s    )Ir   c                 8    U R                   R                  5         g)zQAcquires any lock necessary to access this Storage.

This lock is not reentrant.
N)rX   r5   rQ   s    r   acquire_lock!_MultiStore._Storage.acquire_lock   s    
 ""$r   c                 8    U R                   R                  5         g)zcRelease the Storage lock.

Trying to release a lock that isn't held will result in a
RuntimeError.
N)rX   r7   r\   s    r   release_lock!_MultiStore._Storage.release_lock   s     $$&r   c                     U R                   R                  U R                  5      nU(       a  UR                  U 5        U$ )zwRetrieve credential.

The Storage lock must be held when this is called.

Returns:
    oauth2client.client.Credentials
)rX   _get_credentialrY   	set_store)rQ   
credentials     r   
locked_get_MultiStore._Storage.locked_get   s5     ))99$))DJ$$T*r   c                 P    U R                   R                  U R                  U5        g)zWrite a credential.

The Storage lock must be held when this is called.

Args:
    credentials: Credentials, the credentials to store.
N)rX   _update_credentialrY   )rQ   credentialss     r   
locked_put_MultiStore._Storage.locked_put  s     //		;Gr   c                 N    U R                   R                  U R                  5        g)zDelete a credential.

The Storage lock must be held when this is called.

Args:
    credentials: Credentials, the credentials to store.
N)rX   _delete_credentialrY   r\   s    r   locked_delete"_MultiStore._Storage.locked_delete  s     //		:r   )rY   rX   N)r   r   r   r   r   rR   r]   r`   rf   rk   ro   r   r	   r   r   _StoragerU      s$    G		%	'		H	;r   rq   c                 r   [         R                  R                  U R                  R	                  5       5      (       d`  [         R
                  " S5      n [        U R                  R	                  5       S5      R                  5         [         R
                  " U5        gg! [         R
                  " U5        f = f)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)r;   r<   existsrI   r%   umaskopenclose)rQ   	old_umasks     r   rO   "_MultiStore._create_file_if_needed  sw     ww~~djj11344I$TZZ((*E288:# 5
 #s   2B B6c                 `   U R                   R                  5          U R                  R                  5         U R                  R                  5       (       dF  SU l        U R                  (       a.  [        R                  SU R                  R!                  5       5        ["        R$                  R'                  U R                  R!                  5       5      S:X  a-  [        R)                  S	5        0 U l        U R-                  5         gU R                  (       a  U R*                  c  U R/                  5         gg! [        [
        4 a  nUR                  [        R                  :X  a  [        R                  S5         SnAGNFUR                  [        R                  :X  a  [        R                  S5         SnAGNUR                  [        R                  :X  a  [        R                  S5         SnAGNUR                  [        R                  :X  a  [        R                  S5         SnAGNe SnAff = f)
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)rL   r?   rI   open_and_lockIOErrorOSErrorerrnoENOSYSloggerwarnENOLCKEDEADLKEACCES	is_lockedrM   rN   r%   r;   r<   getsizedebugrP   _write_refresh_data_cache)rQ   es     r   r5   _MultiStore._lock&  s   !!#	JJ$$& zz##%%"DO%% 2 48::3F3F3HJ
 77??4::..01Q6LL=>DJKKMDJJ$6 $$& %77 ! 	ww%,,& 0 1 1ELL( E F FEMM) 1 2 2ELL(=>>	s/   D3 3H-3H(<3H(53H(.3H('H((H-c                 l    U R                   R                  5         U R                  R                  5         g)z#Release the lock on the multistore.N)rI   unlock_and_closerL   rC   r\   s    r   r7   _MultiStore._unlockN  s$    

##%!!#r   c                     U R                   R                  5       (       d   eU R                  R                  5       R	                  S5        [
        R                  " U R                  R                  5       5      $ )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   )rL   lockedrI   file_handleseekjsonloadr\   s    r   _locked_json_read_MultiStore._locked_json_readS  sV       ''))))

 %%a(yy//122r   c                 j   U R                   R                  5       (       d   eU R                  (       a  gU R                  R	                  5       R                  S5        [        R                  " XR                  R	                  5       SSSS9  U R                  R	                  5       R                  5         g)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)	rL   r   rM   rI   r   r   r   dumptruncate)rQ   datas     r   _locked_json_write_MultiStore._locked_json_write_  s       ''))))??

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

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

 ))+r   c                    0 U l          U R                  5       nSn US   nUS:  a  [        SR                  U5      5      e/ n US   nU H%  n U R                  U5      u  pVX`R                   U'   M'     g! [         a    [        R	                  S5         gf = f! [         a    [        R	                  S5         Nf = f! [        [        4 a     Nf = f!   [        R                  S	S
S9   M  = f)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.r3   zMCredential file has file_version of {0}. Only file_version of 1 is supported.r   z#Error decoding credential, skippingT)exc_info)rP   r   	Exceptionr   r   r   format	TypeErrorKeyError_decode_credential_from_jsoninfo)rQ   raw_dataversionrj   
cred_entryr(   re   s          r   r   _MultiStore._refresh_data_cacheo  s    
	--/H 	C~.G Q;+77=vgH H 	"6*K &J+"&"C"CJ"O",

3 &-  	KK 5 6	  	CKK B C	C 8$ 		+A%)  +s@   A5 B B? !C5BBB<;B<?CCC.c                     US   n[        U5      nSn[        R                  R                  [        R
                  " US   5      5      nX44$ )zLoad 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(   Nre   )r   r   Credentialsnew_from_jsonr   dumps)rQ   r   raw_keyr(   re   s        r   r   (_MultiStore._decode_credential_from_json  sM     U# )
''55JJz,/02
  r   c                    SS0n/ nX!S'   U R                   R                  5        HG  u  p4[        U5      n[        R                  " UR                  5       5      nUR                  XVS.5        MI     U R                  U5        g)z@Write the cached data back out.

The multistore must be locked.
r   r3   r   )r(   re   N)rP   r   dictr   loadsto_jsonappendr   )rQ   r   	raw_credscred_keycredr   raw_creds          r   r   _MultiStore._write  ss    
 #A&	$ $

 0 0 2X8nGzz$,,.1HWEF !3 	)r   c                 t    U R                   R                  5        Vs/ s H  n[        U5      PM     sn$ s  snf )zGets all the registered credential keys in the multistore.

Returns:
    A list of dictionaries corresponding to all the keys currently
    registered
)rP   keysr   rQ   r(   s     r   r6   $_MultiStore._get_all_credential_keys  s-     &*ZZ__%67%6cS	%6777s   5c                 :    U R                   R                  US5      $ )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)rP   getr   s     r   rc   _MultiStore._get_credential  s     zz~~c4((r   c                 @    X R                   U'   U R                  5         g)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)rP   r   )rQ   r(   r   s      r   ri   _MultiStore._update_credential  s     

3r   c                 `     U R                   U	 U R                  5         g! [         a     Nf = f)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)rP   r   r   r   s     r   rn   _MultiStore._delete_credential  s1    	

3 	  		s     
--c                 $    U R                  X5      $ )zGet 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
)rq   r   s     r   r1   _MultiStore._get_storage  s     }}T''r   )rP   rI   rM   rL   rN   NT)r   r   r   r   r   r   
positionalrR   r   Storagerq   rO   r5   r7   r   r   r   r   r   r6   rc   ri   rn   r1   r   r	   r   r   rB   rB      st    7	__Q *5;6>> 5;n$&'P$

3, )+V!"*8)
(r   rB   r   )r   r~   r   loggingr;   rJ   oauth2clientr   r   oauth2client.contribr   
__author__	getLoggerr   r   r@   rK   r>   r   r   r   r   r   r)   r.   r$   r9   r0   objectrB   r	   r   r   <module>r      s  @    	    ,*
			8	$ NN$ &I &B B- ,0: :, >B? ?, 7;( (.  (  (k(& k(r   