o
    iX                     @   s  d Z ddlm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	Z	ddl
Z
zddlmZmZ ddlmZmZmZ ddlmZ W n% eye   ddlmZmZ ddlmZmZ dd	lmZ ddlmZ Y nw eeZdHd
dZdd Zdd ZdHddZdd Zdd Z dd Z!dd Z"G dd deZ#G dd dee$Z%G dd de%Z&G d d! d!e$Z'ed"kr[ddl(Z(ddl)Z)d#d$l*m+Z+ ej,ej-d% e(j.e(j/e d& d' Z0Z1e0j2d(d)d*d+ e0j2d,d-d. e0j2d/e3dd0d1 e0j2d2e3d3d4d1 e0j2d5d6d7d8 e0j2d9dd:d8 e14 Z5e+d;e5j6ie5j7Z8e'e5j9d<8Z:e8j;e5j<r$e5j<= ndd=j>e5j?e:@ d>d?ZAeBe)jCe:jDeAd@ dAdBdCe5jEeAdD dEdFdG W d   dS 1 sTw   Y  dS dS )Ia$  A one-stop helper for desktop app to acquire an authorization code.

It starts a web server to listen redirect_uri, waiting for auth code.
It optionally opens a browser window to guide a human user to manually login.
After obtaining an auth code, the web server will automatically shut down.
    )defaultdictN)Template)
HTTPServerBaseHTTPRequestHandler)urlparseparse_qs	urlencodeescape)r   r   )r   c                 C   sB   t | d}|j|dddW  d    S 1 sw   Y  d S )Nportz<html><body>
                Open this link to <a href='$auth_uri'>Sign In</a>
                (You may want to use incognito window)
                <hr><a href='$abort_uri'>Abort</a>
                </body></html>)auth_uriwelcome_templatecode)AuthCodeReceiverget_auth_responseget)Zlisten_portr   receiver r   N/home/app/Keep/.python/lib/python3.10/site-packages/msal/oauth2cli/authcode.pyobtain_auth_code   s   $r   c                  C   s   z7t d)} |  D ]}|ddd  }| dkr& W d    W dS q
W d    n1 s1w   Y  W n	 ty@   Y nw tjdS )Nz/proc/1/cgroup:   /Tz/.dockerenv)open	readlinessplitstripIOErrorospathexists)flineZcgroup_pathr   r   r   _is_inside_docker+   s   
r$   c                  C   sH   dd l } |  }t|d|d  }t|d|d  }|dko#d|v S )Nr   systemreleaser   linuxZ	microsoft)platformunamegetattrlower)r(   r)   Zplatform_namer&   r   r   r   is_wsl9   s
   r,   c                    s  zt  }|jdvrtd|j W dS W n ty%   td  Y dS w t fdddD r8td dS d	d
l}|rG|| }n| }|st	 rd	d
l
}z|d g}|d	k}W n	 tyk   Y nw |sz|d g}|dv }W |S  ty   Y |S w |S )zJBrowse uri with named browser. Default browser is customizable by $BROWSER)httphttpsz"Invalid URI scheme for browser: %sFzInvalid URI: %sc                 3   s    | ]}| v V  qd S Nr   ).0cr   r   r   	<genexpr>O   s    z_browse.<locals>.<genexpr>z
	zInvalid characters in URIr   NZwslviewzexplorer.exe)r      )r   schemeloggerwarning
ValueErrorany
webbrowserr   r   r,   
subprocesscallFileNotFoundError)r   browser_nameZ
parsed_urir:   browser_openedr;   	exit_coder   r2   r   _browseE   sF   




rA   c                 C      dd |   D S )z;Flatten parse_qs()'s single-item lists into the item itselfc                 S   s4   i | ]\}}|t |trt|d kr|d n|qS )r4   r   )
isinstancelistlenr0   kvr   r   r   
<dictcomp>p   s    (z_qs2kv.<locals>.<dictcomp>items)qsr   r   r   _qs2kvn   s   rM   c                 C   s
   |  dS )N<)
startswithtextr   r   r   _is_htmlt   s   
rR   c                 C   rB   )Nc                 S   s   i | ]	\}}|t |qS r   r	   rF   r   r   r   rI   y   s    z_escape.<locals>.<dictcomp>rJ   )Zkey_value_pairsr   r   r   _escapex   s   rS   c                 C   s   t | tr|  st| S | S r/   )rC   strisprintablereprrP   r   r   r   	_printify{   s   rW   c                   @   s6   e Zd Zdd Zdd Zdd Zddd	Zd
d ZdS )_AuthCodeHandlerc                 C   s   t t| jj}|dd gd }|dd gd }|dkr'| | jj d S |dkr4| jddd d S |r?| jd	dd d S | jd
dd d S )NZwelcomer   errortrueabortzAuthentication abortedFis_okzresponse_mode=query is not supported for authentication responses. This application operates in response_mode=form_post mode only.z_Authentication could not be completed. You can close this window and return to the application.)r   r   r    queryr   _send_full_responseserverwelcome_page)selfrL   Zwelcome_paramZerror_paramr   r   r   do_GET   s    

z_AuthCodeHandler.do_GETc                 C   sd   t | jdd}| j|d}t|}|ds |dr)| t| d S | j	ddd d S )	NzContent-Lengthr   utf-8r   rY   zInvalid POST requestFr\   )
intheadersr   rfilereaddecoder   _process_auth_responserM   r_   )rb   content_lengthZ	post_datarL   r   r   r   do_POST   s   z_AuthCodeHandler.do_POSTc                 C   s   t d| | jjr| jj|dkr| jddd dS d|v r$| jjn| jj}t|j	r2t
|}n|}tt|}| |jdi | || j_dS )	z:Process the auth response from either GET or POST request.zGot auth response: %sstatez>State mismatch. Waiting for next response... or you may abort.Fr\   r   Nr   )r6   debugr`   
auth_stater   r_   success_templateerror_templaterR   templaterS   r   rT   safe_substituteauth_response)rb   rt   rr   Z	safe_dataZfilled_datar   r   r   rj      s   



z'_AuthCodeHandler._process_auth_responseTc                 C   sL   |  |rdnd t|rdnd}| d| |   | j|d d S )N   i  z	text/htmlz
text/plainzContent-typerd   )Zsend_responserR   Zsend_headerZend_headerswfilewriteencode)rb   bodyr]   content_typer   r   r   r_      s
   z$_AuthCodeHandler._send_full_responsec                 G   s   t j|gtt|R   d S r/   )r6   rn   maprW   )rb   formatargsr   r   r   log_message   s   z_AuthCodeHandler.log_messageN)T)__name__
__module____qualname__rc   rl   rj   r_   r~   r   r   r   r   rX      s    
rX   c                       s$   e Zd Z fddZdd Z  ZS )_AuthCodeHttpServerc                    sD   |\}}|rt jdkst rd| _tt| j|g|R i | d S )Nwin32F)sysr(   r,   allow_reuse_addresssuperr   __init__)rb   server_addressr}   kwargs_r   	__class__r   r   r      s   "z_AuthCodeHttpServer.__init__c                 C   s   t d)Nz"Timeout. No auth response arrived.)RuntimeErrorrb   r   r   r   handle_timeout   s   z"_AuthCodeHttpServer.handle_timeout)r   r   r   r   r   __classcell__r   r   r   r   r      s    
r   c                   @   s   e Zd ZejZdS )_AuthCodeHttpServer6N)r   r   r   socketAF_INET6address_familyr   r   r   r   r      s    
r   c                   @   sR   e Zd ZdddZdd ZdddZ				ddd	Zd
d Zdd Zdd Z	dS )r   Nc                 C   sJ   t  rdnd}t|pg | _d|v rtnt}|||pdft| _d| _dS )a  Create a Receiver waiting for incoming auth response.

        :param port:
            The local web server will listen at http://...:<port>
            You need to use the same port when you register with your app.
            If your Identity Provider supports dynamic port, you can use port=0 here.
            Port 0 means to use an arbitrary unused port, per this official example:
            https://docs.python.org/2.7/library/socketserver.html#asynchronous-mixins

        :param scheduled_actions:
            For example, if the input is
            ``[(10, lambda: print("Got stuck during sign in? Call 800-000-0000"))]``
            then the receiver would call that lambda function after
            waiting the response for 10 seconds.
        z0.0.0.0	127.0.0.1r   r   FN)r$   sorted_scheduled_actionsr   r   rX   _server_closing)rb   r   Zscheduled_actionsaddressServerr   r   r   r      s
   
zAuthCodeReceiver.__init__c                 C   s   | j jd S )z*The port this server actually listening tor4   )r   r   r   r   r   r   get_port   s   zAuthCodeReceiver.get_portc                 K   s   i }t j| j|f|d}d|_|  t }|r"t | |k rdn	 td | s-n7| jrXt | | jd d krX| j	d\}}|  | jrXt | | jd d ks=|rct | |k s#nq#|pgdS )a	  Wait and return the auth response. Raise RuntimeError when timeout.

        :param str auth_uri:
            If provided, this function will try to open a local browser.
            Starting from 2026, the built-in http server will require response_mode=form_post.
        :param int timeout: In seconds. None means wait indefinitely.
        :param str state:
            You may provide the state you used in auth_uri,
            then we will use it to validate incoming response.
        :param str welcome_template:
            If provided, your end user will see it instead of the auth_uri.
            When present, it shall be a plaintext or html template following
            `Python Template string syntax <https://docs.python.org/3/library/string.html#template-strings>`_,
            and include some of these placeholders: $auth_uri and $abort_uri.
        :param str success_template:
            The page will be displayed when authentication was largely successful.
            Placeholders can be any of these:
            https://tools.ietf.org/html/rfc6749#section-5.1
        :param str error_template:
            The page will be displayed when authentication encountered error.
            Placeholders can be any of these:
            https://tools.ietf.org/html/rfc6749#section-5.2
        :param callable auth_uri_callback:
            A function with the shape of lambda auth_uri: ...
            When a browser was unable to be launch, this function will be called,
            so that the app could tell user to manually visit the auth_uri.
        :param str browser_name:
            If you did
            ``webbrowser.register("xyz", None, BackgroundBrowser("/path/to/browser"))``
            beforehand, you can pass in the name "xyz" to use that browser.
            The default value ``None`` means using default browser,
            which is customizable by env var $BROWSER.
        :return:
            The auth response of the first leg of Auth Code flow,
            typically {"code": "...", "state": "..."} or {"error": "...", ...}
            See https://tools.ietf.org/html/rfc6749#section-4.1.2
            and https://openid.net/specs/openid-connect-core-1_0.html#AuthResponse
            Returns None when the state was mismatched, or when timeout occurred.
        )targetr}   r   Tr4   r   N)
	threadingThread_get_auth_responsedaemonstarttimesleepis_aliver   pop)rb   timeoutr   resulttbeginr   callbackr   r   r   r     s&   6

z"AuthCodeReceiver.get_auth_responsec
                 C   s^  dj |  d}
dj |
d}td| |r,tt|j}|dd gd dks,J d	t|p0d
j	||d| j
_|rt|rA|
d n|}td|  d}zt||	d}W n	   td Y |st|sptdj |||  d n|| d}t|p|d| | j
_t|pd| | j
_|| j
_i | j
_|| j
_| js| j
  | j
jrn| jr|| j
j d S )Nzhttp://localhost:{p})pz{loc}?error=abort)loczAbort by visit %sZresponse_moder   Z	form_postziThe built-in http server supports HTTP POST only. The auth_uri must be built with response_mode=form_post )r   	abort_uriz?welcome=truez*Open a browser on this device to visit: %sF)r>   z_browse(...) unsuccessfula  Found no browser in current environment. If this program is being run inside a container which either (1) has access to host network (i.e. started by `docker run --net=host -it ...`), or (2) published port {port} to host network (i.e. started by `docker run -p 127.0.0.1:{port}:{port} -it ...`), you can use browser on host to visit the following link. Otherwise, this auth attempt would either timeout (current timeout setting is {timeout}) or be aborted by CTRL+C. Auth URI: {auth_uri})r   r   r   z`For your security: Do not share the contents of this page, the address bar, or take screenshots.z\Authentication complete. You can return to the application. Please close this browser tab.

zBAuthentication failed. $error: $error_description. ($error_uri).

)r|   r   r6   rn   r   r   r^   r   r   rs   r   ra   inforA   	exceptionr7   rp   rq   r   rt   ro   r   handle_requestupdate)rb   r   r   r   rm   r   rp   rq   Zauth_uri_callbackr>   netlocr   paramsZ_urir?   Zrecommendationr   r   r   r   H  sX   
	

z#AuthCodeReceiver._get_auth_responsec                 C   s   d| _ | j  dS )zGEither call this eventually; or use the entire class as context managerTN)r   r   server_closer   r   r   r   close  s   zAuthCodeReceiver.closec                 C   s   | S r/   r   r   r   r   r   	__enter__  s   zAuthCodeReceiver.__enter__c                 C   s   |    d S r/   )r   )rb   exc_typeexc_valexc_tbr   r   r   __exit__  s   zAuthCodeReceiver.__exit__)NNr/   )NNNNNNNN)
r   r   r   r   r   r   r   r   r   r   r   r   r   r   r      s    
#
F
Dr   __main__r4   )Client)levelz/The auth code received will be shown at stdout.)formatter_classdescriptionz
--endpointzThe auth endpoint for your app.z>https://login.microsoftonline.com/common/oauth2/v2.0/authorize)helpdefault	client_idz!The client_id of your application)r   z--portzThe port in redirect_uri)typer   r   z	--timeout<   zTimeout value, in secondz--hostr   zThe host of redirect_uri)r   r   z--scopezThe scope listZauthorization_endpointr   zhttp://{h}:{p})hr   )scopeZredirect_urir   zB<a href='$auth_uri'>Sign In</a>, or <a href='$abort_uri'>Abort</a>z<html>Oh no. $error</html>zOh yeah. Got $coderm   )r   r   rq   rp   r   rm      )indentr/   )F__doc__collectionsr   loggingr   r   r   stringr   r   r   Zhttp.serverr   r   urllib.parser   r   r   htmlr
   ImportErrorBaseHTTPServerurllibZcgi	getLoggerr   r6   r   r$   r,   rA   rM   rR   rS   rW   rX   objectr   r   r   argparsejsonZoauth2r   basicConfigINFOArgumentParserArgumentDefaultsHelpFormatterr   parseradd_argumentre   
parse_argsr}   Zendpointr   clientr   r   Zinitiate_auth_code_flowr   r   r|   hostr   Zflowprintdumpsr   r   r   r   r   r   <module>   s   


)A 
B


$