o
    Df#                     @   sd   d dl Z ddlmZmZmZ ddlmZmZ ddlm	Z	m
Z
mZ e eZdZG dd	 d	eeZdS )
    N   )InvalidRequestErrorUnauthorizedClientErrorAccessDeniedError)	BaseGrantTokenEndpointMixin   )AuthorizationPendingErrorExpiredTokenErrorSlowDownErrorz,urn:ietf:params:oauth:grant-type:device_codec                   @   sL   e Zd ZdZeZg dZdd Zdd Zdd Z	d	d
 Z
dd Zdd ZdS )DeviceCodeGrantal
  This OAuth 2.0 [RFC6749] protocol extension enables OAuth clients to
    request user authorization from applications on devices that have
    limited input capabilities or lack a suitable browser.  Such devices
    include smart TVs, media consoles, picture frames, and printers,
    which lack an easy input method or a suitable browser required for
    traditional OAuth interactions. Here is the authorization flow::

        +----------+                                +----------------+
        |          |>---(A)-- Client Identifier --->|                |
        |          |                                |                |
        |          |<---(B)-- Device Code,      ---<|                |
        |          |          User Code,            |                |
        |  Device  |          & Verification URI    |                |
        |  Client  |                                |                |
        |          |  [polling]                     |                |
        |          |>---(E)-- Device Code       --->|                |
        |          |          & Client Identifier   |                |
        |          |                                |  Authorization |
        |          |<---(F)-- Access Token      ---<|     Server     |
        +----------+   (& Optional Refresh Token)   |                |
              v                                     |                |
              :                                     |                |
             (C) User Code & Verification URI       |                |
              :                                     |                |
              v                                     |                |
        +----------+                                |                |
        | End User |                                |                |
        |    at    |<---(D)-- End user reviews  --->|                |
        |  Browser |          authorization request |                |
        +----------+                                +----------------+

    This DeviceCodeGrant is the implementation of step (E) and (F).

    (E) While the end user reviews the client's request (step D), the
        client repeatedly polls the authorization server to find out if
        the user completed the user authorization step.  The client
        includes the device code and its client identifier.

    (F) The authorization server validates the device code provided by
        the client and responds with the access token if the client is
        granted access, an error if they are denied access, or an
        indication that the client should continue to poll.
    )client_secret_basicclient_secret_postnonec                 C   s   | j jd}|std|  }|| jst | |}|s%td|	 |	 kr0t | 
|}|| j _|| j _|| j _dS )a#  After displaying instructions to the user, the client creates an
        access token request and sends it to the token endpoint with the
        following parameters:

        grant_type
            REQUIRED.  Value MUST be set to
            "urn:ietf:params:oauth:grant-type:device_code".

        device_code
            REQUIRED.  The device verification code, "device_code" from the
            device authorization response.

        client_id
            REQUIRED if the client is not authenticating with the
            authorization server as described in Section 3.2.1. of [RFC6749].
            The client identifier as described in Section 2.2 of [RFC6749].

        For example, the client makes the following HTTPS request::

            POST /token HTTP/1.1
            Host: server.example.com
            Content-Type: application/x-www-form-urlencoded

            grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Adevice_code
            &device_code=GmRhmhcxhwAzkoEqiMEg_DnyEysNkuNhszIySk9eS
            &client_id=1406020730
        device_codez Missing "device_code" in payloadz Invalid "device_code" in payloadN)requestdatagetr   "authenticate_token_endpoint_clientcheck_grant_type
GRANT_TYPEr   query_device_credentialget_client_idvalidate_device_credentialuserclient
credential)selfr   r   r   r    r   [/home/ubuntu/webapp/venv/lib/python3.10/site-packages/authlib/oauth2/rfc8628/device_code.pyvalidate_token_requestA   s   

z&DeviceCodeGrant.validate_token_requestc                 C   s`   | j j}| j j }| j| j j||dd}td|| | 	| | j
d|d d|| jfS )zIf the access token request is valid and authorized, the
        authorization server issues an access token and optional refresh
        token.
        refresh_token)r   scopeinclude_refresh_tokenzIssue token %r to %rprocess_token)token   )r   r   r   	get_scopegenerate_tokenr   r   logdebug
save_tokenexecute_hookTOKEN_RESPONSE_HEADER)r   r   r"   r%   r   r   r   create_token_responseq   s   
z%DeviceCodeGrant.create_token_responsec                 C   sT   |  rt | }| |}|d ur|\}}|st |S | |r't t )N)
is_expiredr
   get_user_codequery_user_grantr   should_slow_downr   r	   )r   r   	user_code
user_grantr   approvedr   r   r   r      s   

z*DeviceCodeGrant.validate_device_credentialc                 C      t  )ai  Get device credential from previously savings via ``DeviceAuthorizationEndpoint``.
        Developers MUST implement it in subclass::

            def query_device_credential(self, device_code):
                return DeviceCredential.get(device_code)

        :param device_code: a string represent the code.
        :return: DeviceCredential instance
        NotImplementedError)r   r   r   r   r   r      s   
z'DeviceCodeGrant.query_device_credentialc                 C   r6   )a!  Get user and grant via the given user code. Developers MUST
        implement it in subclass::

            def query_user_grant(self, user_code):
                # e.g. we saved user grant info in redis
                data = redis.get('oauth_user_grant:' + user_code)
                if not data:
                    return None

                user_id, allowed = data.split()
                user = User.get(user_id)
                return user, bool(allowed)

        Note, user grant information is saved by verification endpoint.
        r7   )r   r3   r   r   r   r1      s   z DeviceCodeGrant.query_user_grantc                 C   r6   )zThe authorization request is still pending and polling should
        continue, but the interval MUST be increased by 5 seconds for this
        and all subsequent requests.
        r7   )r   r   r   r   r   r2      s   z DeviceCodeGrant.should_slow_downN)__name__
__module____qualname____doc__DEVICE_CODE_GRANT_TYPEr   TOKEN_ENDPOINT_AUTH_METHODSr    r.   r   r   r1   r2   r   r   r   r   r      s    +0r   )loggingrfc6749.errorsr   r   r   rfc6749r   r   errorsr	   r
   r   	getLoggerr9   r)   r=   r   r   r   r   r   <module>   s    
