ó
«mOc           @   s˜  d  Z  e Z d d d d d d d g Z d d	 l Z d d
 l m Z d d	 l Z d d	 l Z d d l	 m	 Z	 d d	 l
 Z
 d d l m Z d d	 l Z d d l m Z d d l m Z d d	 l Z d d l m Z m 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  d Z! d Z" d Z# d Z$ e% e& e' f Z( d e f d „  ƒ  YZ) d e f d „  ƒ  YZ d e f d „  ƒ  YZ* d e+ f d „  ƒ  YZ, d e, f d „  ƒ  YZ- d e, f d „  ƒ  YZ. d e+ f d „  ƒ  YZ/ d e/ f d  „  ƒ  YZ0 d! e1 f d" „  ƒ  YZ2 d# e2 f d$ „  ƒ  YZ3 d% e2 f d& „  ƒ  YZ4 d' e2 f d( „  ƒ  YZ5 d) e2 f d* „  ƒ  YZ6 d+ e2 f d, „  ƒ  YZ7 d- e2 f d. „  ƒ  YZ8 d	 S(/   s4   launchpadlib credentials and authentication support.t   AccessTokent   AnonymousAccessTokent    AuthorizeRequestTokenWithBrowsert   CredentialStoret   RequestTokenAuthorizationEnginet   Consumert   CredentialsiÿÿÿÿN(   t   StringIO(   t   select(   t   stdin(   t	   urlencode(   t   urljoin(   t	   b64decodet	   b64encode(   t	   HTTPError(   R    R   t   OAuthAuthorizert   SystemWideConsumer(   t   uriss   +request-tokens   +access-tokens   +authorize-tokeni   c           B   sh   e  Z d  Z d	 Z d Z d Z d Z d Z d „  Z	 e
 d „  ƒ Z d	 e j e d „ Z e j d „ Z RS(
   sè   Standard credentials storage and usage class.

    :ivar consumer: The consumer (application)
    :type consumer: `Consumer`
    :ivar access_token: Access information on behalf of the user
    :type access_token: `AccessToken`
    t   urit   dicts   <BR>s   
c         C   s&   t  ƒ  } |  j | ƒ | j ƒ  } | S(   se   Turn this object into a string.

        This should probably be moved into OAuthAuthorizer.
        (   R   t   savet   getvalue(   t   selft   siot
   serialized(    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyt	   serializeQ   s    	c         C   s    |  ƒ  } | j  t | ƒ ƒ | S(   s}   Create a `Credentials` object from a serialized string.

        This should probably be moved into OAuthAuthorizer.
        (   t   loadR   (   t   clst   valuet   credentials(    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyt   from_string[   s    	c   	   	   C   s–  |  j  d k	 s t d ƒ ‚ |  j d k s6 t d ƒ ‚ t j | ƒ } t d |  j  j d d d d ƒ } | t } i | d 6} | |  j	 k r™ d	 | d
 <n  t
 j ƒ  j | d d d | d t | ƒ ƒ\ } } | j d k rí t | | ƒ ‚ n  | |  j	 k r:t j | ƒ } | d k	 r$| | d <n  t j | ƒ |  _ | St j | ƒ |  _ d | t |  j j f } | d k	 rŽ| |  j _ | d | 7} n  | Sd S(   sã  Request an OAuth token to Launchpad.

        Also store the token in self._request_token.

        This method must not be called on an object with no consumer
        specified or if an access token has already been obtained.

        :param context: The context of this token, that is, its scope of
            validity within Launchpad.
        :param web_root: The URL of the website on which the token
            should be requested.
        :token_format: How the token should be
            presented. URI_TOKEN_FORMAT means just return the URL to
            the page that authorizes the token.  DICT_TOKEN_FORMAT
            means return a dictionary describing the token
            and the site's authentication policy.

        :return: If token_format is URI_TOKEN_FORMAT, the URL for the
            user to authorize the `AccessToken` provided by
            Launchpad. If token_format is DICT_TOKEN_FORMAT, a dict of
            information about the new access token.
        s   Consumer not specified.s   Access token already obtained.t   oauth_consumer_keyt   oauth_signature_methodt	   PLAINTEXTt   oauth_signaturet   &t   Referers   application/jsont   Acceptt   methodt   POSTt   headerst   bodyiÈ   s
   lp.contexts   %s%s?oauth_token=%ss   &lp.context=%sN(   t   consumert   Nonet   AssertionErrort   access_tokenR   t   lookup_web_rootR   t   keyt   request_token_paget   DICT_TOKEN_FORMATt   httplib2t   Httpt   requestR
   t   statusR   t
   simplejsont   loadsR    t   from_paramst   _request_tokenR   t   authorize_token_paget   context(	   R   R;   t   web_roott   token_formatt   paramst   urlR(   t   responset   content(    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyt   get_request_tokene   s8    	
'	c      
   C   sâ   |  j  d k	 s t d ƒ ‚ t j | ƒ } t d |  j j d d d |  j  j d d |  j  j ƒ } | t	 } i | d 6} t
 j ƒ  j | d	 d
 d | d t | ƒ ƒ\ } } | j d k rÌ t | | ƒ ‚ n  t j | ƒ |  _ d S(   sd  Exchange the previously obtained request token for an access token.

        This method must not be called unless get_request_token() has been
        called and completed successfully.

        The access token will be stored as self.access_token.

        :param web_root: The base URL of the website that granted the
            request token.
        s5   get_request_token() doesn't seem to have been called.R   R    R!   t   oauth_tokenR"   s   &%sR$   R&   R'   R(   R)   iÈ   N(   R9   R+   R,   R   R.   R   R*   R/   t   secrett   access_token_pageR2   R3   R4   R
   R5   R   R    R   R-   (   R   R<   R>   R?   R(   R@   RA   (    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyt'   exchange_request_token_for_access_token›   s    	
'N(   t   __name__t
   __module__t   __doc__R+   R9   t   URI_TOKEN_FORMATR1   t   ITEM_SEPARATORt   NEWLINER   t   classmethodR   R   t   STAGING_WEB_ROOTRB   RF   (    (    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyR   B   s   	

	6c           B   s,   e  Z d  Z e d „  ƒ Z e d „  ƒ Z RS(   s   An OAuth access token.c         C   s3   | d } | d } | j  d ƒ } |  | | | ƒ S(   s:   Create and return a new `AccessToken` from the given dict.RC   t   oauth_token_secrets
   lp.context(   t   get(   R   R>   R/   RD   R;   (    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyR8   »   s    

c         C   sÏ   t  j | d t ƒ} | d } t | ƒ d k s= t d ƒ ‚ | d } | d } t | ƒ d k so t d ƒ ‚ | d } | j d ƒ } | d
 k	 r¿ t | ƒ d k s² t d	 ƒ ‚ | d } n  |  | | | ƒ S(   s<   Create and return a new `AccessToken` from the given string.t   keep_blank_valuesRC   i   s/   Query string must have exactly one oauth_token.i    RO   s*   Query string must have exactly one secret.s
   lp.contexts*   Query string must have exactly one contextN(   t   cgit   parse_qst   Falset   lenR,   RP   R+   (   R   t   query_stringR>   R/   RD   R;   (    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyR   Ã   s    
	


	(   RG   RH   RI   RM   R8   R   (    (    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyR    ¸   s   c           B   s   e  Z d  Z d „  Z RS(   so   An OAuth access token that doesn't authenticate anybody.

    This token can be used for anonymous access.
    c         C   s   t  t |  ƒ j d d ƒ d  S(   Nt    (   t   superR   t   __init__(   R   (    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyRY   Û   s    (   RG   RH   RI   RY   (    (    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyR   Ö   s   c           B   s>   e  Z d  Z d d „ Z d „  Z d „  Z d „  Z d „  Z RS(   sÖ   Store OAuth credentials locally.

    This is a generic superclass. To implement a specific way of
    storing credentials locally you'll need to subclass this class,
    and implement `do_save` and `do_load`.
    c         C   s   | |  _  d S(   s  Constructor.

        :param credential_save_failed: A callback to be invoked if the
            save to local storage fails. You should never invoke this
            callback yourself! Instead, you should raise an exception
            from do_save().
        N(   t   credential_save_failed(   R   RZ   (    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyRY   ç   s    c         C   sc   y |  j  | | ƒ WnH t k
 r* ‚  n5 t k
 r^ } |  j d k rQ | ‚ n  |  j ƒ  n X| S(   sœ   Save the credentials and invoke the callback on failure.

        Do not override this method when subclassing. Override
        do_save() instead.
        N(   t   do_savet   EXPLOSIVE_ERRORSt	   ExceptionRZ   R+   (   R   R   t   unique_consumer_idt   e(    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyR   ñ   s    	c         C   s   t  ƒ  ‚ d S(   sõ   Store newly-authorized credentials locally for later use.

        :param credentials: A Credentials object to save.
        :param unique_consumer_id: A string uniquely identifying an
            OAuth consumer on a Launchpad instance.
        N(   t   NotImplementedError(   R   R   R^   (    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyR[     s    c         C   s   |  j  | ƒ S(   s0  Retrieve credentials from a local store.

        This method is the inverse of `save`.

        There's no special behavior in this method--it just calls
        `do_load`. There _is_ special behavior in `save`, and this
        way, developers can remember to implement `do_save` and
        `do_load`, not `do_save` and `load`.

        :param unique_key: A string uniquely identifying an OAuth consumer
            on a Launchpad instance.

        :return: A `Credentials` object if one is found in the local
            store, and None otherise.
        (   t   do_load(   R   t
   unique_key(    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyR   
  s    c         C   s   t  ƒ  ‚ d S(   s@  Retrieve credentials from a local store.

        This method is the inverse of `do_save`.

        :param unique_key: A string uniquely identifying an OAuth consumer
            on a Launchpad instance.

        :return: A `Credentials` object if one is found in the local
            store, and None otherise.
        N(   R`   (   R   Rb   (    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyRa     s    N(	   RG   RH   RI   R+   RY   R   R[   R   Ra   (    (    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyR   ß   s   
				t   KeyringCredentialStorec           B   s5   e  Z d  Z d Z e d „  ƒ Z d „  Z d „  Z RS(   sö   Store credentials in the GNOME keyring or KDE wallet.

    This is a good solution for desktop applications and interactive
    scripts. It doesn't work for non-interactive scripts, or for
    integrating third-party websites into Launchpad.
    s   <B64>c           C   s"   d t  ƒ  k r d d l a n  d S(   sG  Ensure the keyring module is imported (postponing side effects).

        The keyring module initializes the environment-dependent backend at
        import time (nasty).  We want to avoid that initialization because it
        may do things like prompt the user to unlock their password store
        (e.g., KWallet).
        t   keyringiÿÿÿÿN(   t   globalsRd   (    (    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyt   _ensure_keyring_imported4  s    	c         C   s@   |  j  ƒ  | j ƒ  } |  j t | ƒ } t j d | | ƒ d S(   s2   Store newly-authorized credentials in the keyring.t   launchpadlibN(   Rf   R   t	   B64MARKERR   Rd   t   set_password(   R   R   Rb   R   (    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyR[   A  s
    
c         C   s§   |  j  ƒ  t j d | ƒ } | d k	 r£ | j d ƒ } | j |  j ƒ r~ y t | t |  j ƒ ƒ } Wq~ t	 k
 rz d SXn  y t
 j | ƒ } | SWq£ d SXn  d S(   s&   Retrieve credentials from the keyring.Rg   t   utf8N(   Rf   Rd   t   get_passwordR+   t   encodet
   startswithRh   R   RU   t	   TypeErrorR   R   (   R   Rb   t   credential_stringR   (    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyRa   L  s"    
(   RG   RH   RI   Rh   t   staticmethodRf   R[   Ra   (    (    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyRc   *  s
   	t   UnencryptedFileCredentialStorec           B   s,   e  Z d  Z d d „ Z d „  Z d „  Z RS(   s‘   Store credentials unencrypted in a file on disk.

    This is a good solution for scripts that need to run without any
    user interaction.
    c         C   s#   t  t |  ƒ j | ƒ | |  _ d  S(   N(   RX   Rq   RY   t   filename(   R   Rr   RZ   (    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyRY   m  s    c         C   s   | j  |  j ƒ d S(   s   Save the credentials to disk.N(   t   save_to_pathRr   (   R   R   Rb   (    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyR[   r  s    c         C   sI   t  j j |  j ƒ rE t  j |  j ƒ t j d k rE t j |  j ƒ Sd S(   s   Load the credentials from disk.i    N(	   t   ost   patht   existsRr   t   statt   ST_SIZER   t   load_from_pathR+   (   R   Rb   (    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyRa   v  s     N(   RG   RH   RI   R+   RY   R[   Ra   (    (    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyRq   f  s   	c           B   sY   e  Z d  Z d Z d d d d „ Z e d „  ƒ Z d „  Z d „  Z	 d „  Z
 d „  Z RS(	   s/  The superclass of all request token authorizers.

    This base class does not implement request token authorization,
    since that varies depending on how you want the end-user to
    authorize a request token. You'll need to subclass this class and
    implement `make_end_user_authorize_token`.
    t   UNAUTHORIZEDc         C   s×   t  j | ƒ |  _ t  j | ƒ |  _ | d k rK | d k rK t d ƒ ‚ n  | d k	 r| | d k	 r| t d | | f ƒ ‚ n  | d k r  d g } t | ƒ } n t | ƒ } | } | |  _	 | |  _
 | pÍ g  |  _ d S(   sD  Base class initialization.

        :param service_root: The root of the Launchpad instance being
            used.

        :param application_name: The name of the application that
            wants to use launchpadlib. This is used in conjunction
            with a desktop-wide integration.

            If you specify this argument, your values for
            consumer_name and allow_access_levels are ignored.

        :param consumer_name: The OAuth consumer name, for an
            application that wants its own point of integration into
            Launchpad. In almost all cases, you want to specify
            application_name instead and do a desktop-wide
            integration. The exception is when you're integrating a
            third-party website into Launchpad.

        :param allow_access_levels: A list of the Launchpad access
            levels to present to the user. ('READ_PUBLIC' and so on.)
            Your value for this argument will be ignored during a
            desktop-wide integration.
        :type allow_access_levels: A list of strings.
        s:   You must provide either application_name or consumer_name.sZ   You must provide only one of application_name and consumer_name. (You provided %r and %r.)t   DESKTOP_INTEGRATIONN(   R   t   lookup_service_roott   service_roott   web_root_for_service_rootR<   R+   t
   ValueErrorR   R   R*   t   application_namet   allow_access_levels(   R   R}   R€   t   consumer_nameR   R*   (    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyRY   ‰  s"    			c         C   s   |  j  j d |  j S(   s7   Return a string identifying this consumer on this host.t   @(   R*   R/   R}   (   R   (    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyR^   Â  s    c         C   sX   d t  | f } d } t |  j ƒ d k rH | | | j |  j ƒ 7} n  t |  j | ƒ S(   sÞ   Return the authorization URL for a request token.

        This is the URL the end-user must visit to authorize the
        token. How exactly does this happen? That depends on the
        subclass implementation.
        s   %s?oauth_token=%ss   &allow_permission=i    (   R:   RU   R   t   joinR   R<   (   R   t   request_tokent   paget   allow_permission(    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyt   authorization_urlÇ  s    c         C   sI   |  j  | ƒ } |  j | | ƒ | j d k r2 d S| j | |  j ƒ | S(   sd  Authorize a token and associate it with the given credentials.

        If the credential store runs into a problem storing the
        credential locally, the `credential_save_failed` callback will
        be invoked. The callback will not be invoked if there's a
        problem authorizing the credentials.

        :param credentials: A `Credentials` object. If the end-user
            authorizes these credentials, this object will have its
            .access_token property set.

        :param credential_store: A `CredentialStore` object. If the
            end-user authorizes the credentials, they will be
            persisted locally using this object.

        :return: If the credentials are successfully authorized, the
            return value is the `Credentials` object originally passed
            in. Otherwise the return value is None.
        N(   RB   t   make_end_user_authorize_tokenR-   R+   R   R^   (   R   R   t   credential_storet   request_token_string(    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyt   __call__Ö  s    c         C   s&   | j  d |  j d t j ƒ } | d S(   s\   Get a new request token from the server.

        :param return: The request token.
        R<   R=   RC   (   RB   R<   R   R1   (   R   R   t   authorization_json(    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyRB   ô  s    		c         C   s   t  ƒ  ‚ d S(   s5  Authorize the given request token using the given credentials.

        Your subclass must implement this method: it has no default
        implementation.

        Because an access token may expire or be revoked in the middle
        of a session, this method may be called at arbitrary points in
        a launchpadlib session, or even multiple times during a single
        session (with a different request token each time).

        In most cases, however, this method will be called at the
        beginning of a launchpadlib session, or not at all.
        N(   R`   (   R   R   R…   (    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyR‰   þ  s    N(   RG   RH   RI   t   UNAUTHORIZED_ACCESS_LEVELR+   RY   t   propertyR^   Rˆ   RŒ   RB   R‰   (    (    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyR   ~  s   8			
c           B   sJ   e  Z d  Z d Z d Z d Z d Z d d d d „ Z d „  Z	 d „  Z
 RS(	   sß   The simplest (and, right now, the only) request token authorizer.

    This authorizer simply opens up the end-user's web browser to a
    Launchpad URL and lets the end-user authorize the request token
    themselves.
    s   The authorization page:
 (%s)
should be opening in your browser. Use your browser to authorize
this program to access Launchpad on your behalf.s1   Press any key to continue or wait (%d) seconds...i   s5   Waiting to hear from Launchpad about your decision...c         C   s#   t  t |  ƒ j | | d | ƒ d S(   so  Constructor.

        :param service_root: See `RequestTokenAuthorizationEngine`.
        :param application_name: See `RequestTokenAuthorizationEngine`.
        :param consumer_name: The value of this argument is
            ignored. If we have the capability to open the end-user's
            web browser, we must be running on the end-user's computer,
            so we should do a full desktop integration.
        :param credential_save_failed: See `RequestTokenAuthorizationEngine`.
        :param allow_access_levels: The value of this argument is
            ignored, for the same reason as consumer_name.
        N(   RX   R   RY   R+   (   R   R}   R€   R‚   RZ   R   (    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyRY     s    	c         C   s	   | GHd S(   s³   Display a message.

        By default, prints the message to standard output. The message
        does not require any user interaction--it's solely
        informative.
        N(    (   R   t   message(    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyt   output1  s    c         C   s#  |  j  | ƒ } |  j |  j | ƒ |  j |  j |  j ƒ t t g g  g  |  j ƒ \ } } } | rq t j ƒ  n  |  j |  j ƒ t	 j
 | ƒ xŽ | j d k rt j t ƒ y | j |  j ƒ PWq‘ t k
 r} | j j d k rø t | j ƒ ‚ q| j j d k rqd GH| GHq‘ Xq‘ Wd S(   s7   Have the end-user authorize the token in their browser.i“  i‘  s#   Unexpected response from Launchpad:N(   Rˆ   R‘   t   WAITING_FOR_USERt   TIMEOUT_MESSAGEt   TIMEOUTR   R	   t   readlinet   WAITING_FOR_LAUNCHPADt
   webbrowsert   openR-   R+   t   timet   sleept   access_token_poll_timeRF   R<   R   R@   R5   t   EndUserDeclinedAuthorizationRA   (   R   R   R…   Rˆ   t   rlistt   _R_   (    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyR‰   :  s*    $
N(   RG   RH   RI   R’   R“   R”   R–   R+   RY   R‘   R‰   (    (    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyR     s   		t   TokenAuthorizationExceptionc           B   s   e  Z RS(    (   RG   RH   (    (    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyRŸ   [  s   t   RequestTokenAlreadyAuthorizedc           B   s   e  Z RS(    (   RG   RH   (    (    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyR    _  s   Rœ   c           B   s   e  Z RS(    (   RG   RH   (    (    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyRœ   c  s   t   ClientErrorc           B   s   e  Z RS(    (   RG   RH   (    (    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyR¡   g  s   t   ServerErrorc           B   s   e  Z RS(    (   RG   RH   (    (    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyR¢   k  s   t   NoLaunchpadAccountc           B   s   e  Z RS(    (   RG   RH   (    (    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyR£   o  s   t   TooManyAuthenticationFailuresc           B   s   e  Z RS(    (   RG   RH   (    (    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyR¤   s  s   (9   RI   t   typet   __metaclass__t   __all__RR   t	   cStringIOR   R2   Rt   R   Rw   t   sysR	   R™   t   urllibR
   t   urlparseR   R—   t   base64R   R   R6   t   lazr.restfulclient.errorsR   t"   lazr.restfulclient.authorize.oauthR    t   _AccessTokenR   R   R   Rg   R   R0   RE   R:   R›   t   MemoryErrort   KeyboardInterruptt
   SystemExitR\   R   R   t   objectR   Rc   Rq   R   R   R]   RŸ   R    Rœ   R¡   R¢   R£   R¤   (    (    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyt   <module>   sX   	"v	K<‘L