o
    +ifJ                     @   s  d 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y_   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dGd	d
Zdd Zdd ZdGd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rUddl&Z&ddl'Z'd"d#l(m)Z) ej*ej+d$ e&j,e&j-e d% d& Z.Z/e.j0d'd(d)d* e.j0d+d,d- e.j0d.e1dd/d0 e.j0d1e1d2d3d0 e.j0d4d5d6d7 e.j0d8dd9d7 e/2 Z3e)d:e3j4ie3j5Z6e%e3j7d;8Z8e6j9e3j:re3j:; ndd<j<e3j=e8> d=d>Z?e@e'jAe8jBe?d? d@dAdBe3jCe?dC dDdEdF W d   dS 1 sNw   Y  dS dS )Ha$  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.
    N)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)listen_portr   receiver r   P/var/www/html/corbot_env/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line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   linux	microsoft)platformunamegetattrlower)r*   r+   platform_namer'   r   r   r   is_wsl8   s
   r/   c                 C   sz   ddl }|r||| }n|| }|s;t r;zddl}|dddd| g}|dk}W |S  ty:   Y |S w |S )zJBrowse uri with named browser. Default browser is customizable by $BROWSERr   Nzpowershell.exez
-NoProfilez-CommandzStart-Process "{}")
webbrowserr   r   r/   
subprocesscallformatFileNotFoundError)r   browser_namer0   browser_openedr1   	exit_coder   r   r   _browseD   s"   


r8   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 )   r   )
isinstancelistlen.0kvr   r   r   
<dictcomp>]   s    (z_qs2kv.<locals>.<dictcomp>items)qsr   r   r   _qs2kv[   s   rF   c                 C   s
   |  dS )N<)
startswithtextr   r   r   _is_htmla   s   
rK   c                 C   r9   )Nc                 S   s   i | ]	\}}|t |qS r   r   r>   r   r   r   rB   f   s    z_escape.<locals>.<dictcomp>rC   )key_value_pairsr   r   r   _escapee   s   rM   c                 C   s   t | tr|  st| S | S N)r;   strisprintablereprrI   r   r   r   	_printifyi   s   rR   c                   @   s&   e Zd Zdd Zd	ddZdd ZdS )
_AuthCodeHandlerc                 C   s   t t| jj}|ds|drYt|}td| | jj	r0| jj	|dkr0| 
d d S d|v r8| jjn| jj}t|jrFt|}n|}| 
|jdi | || j_d S | 
| jj d S )Nr   errorzGot auth response: %sstatezState mismatchr   )r   r   r    queryr   rF   loggerdebugserver
auth_state_send_full_responsesuccess_templateerror_templaterK   templaterM   safe_substituteauth_responsewelcome_page)selfrE   r`   r^   	safe_datar   r   r   do_GETo   s    

z_AuthCodeHandler.do_GETTc                 C   sL   |  |rdnd t|rdnd}| d| |   | j|d d S )N   i  z	text/htmlz
text/plainzContent-typezutf-8)send_responserK   send_headerend_headerswfilewriteencode)rb   bodyis_okcontent_typer   r   r   r[      s
   z$_AuthCodeHandler._send_full_responsec                 G   s   t j|gtt|R   d S rN   )rW   rX   maprR   )rb   r3   argsr   r   r   log_message   s   z_AuthCodeHandler.log_messageN)T)__name__
__module____qualname__rd   r[   rq   r   r   r   r   rS   n   s    
rS   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superru   __init__)rb   server_addressrp   kwargs_r   	__class__r   r   rz      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)rr   rs   rt   rz   r   __classcell__r   r   r~   r   ru      s    
ru   c                   @   s   e Zd ZejZdS )_AuthCodeHttpServer6N)rr   rs   rt   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   ru   rS   _server_closing)rb   r   scheduled_actionsaddressServerr   r   r   rz      s
   
zAuthCodeReceiver.__init__c                 C   s   | j jd S )z*The port this server actually listening tor:   )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.
        :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.
        )targetrp   r|   Tr:   r   N)
	threadingThread_get_auth_responsedaemonstarttimesleepis_aliver   pop)rb   timeoutr|   resulttbeginr}   callbackr   r   r   r      s&   5

z"AuthCodeReceiver.get_auth_responsec
                 C   s  dj |  d}
dj |
d}td| t|pdj||d| j_|rZ|r'|
n|}td|  d	}zt	||	d
}W n	   t
d Y |sZ|sVtdj |||  d n|| t|p^d| j_t|pfd| j_|| j_i | j_|| j_| js| j  | jjrn| jry|| jj d S )Nzhttp://localhost:{p})pz{loc}?error=abort)loczAbort by visit %s )r   	abort_uriz*Open a browser on this device to visit: %sF)r5   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   z8Authentication completed. You can close this window now.z?Authentication failed. $error: $error_description. ($error_uri))r3   r   rW   rX   r   r_   r   ra   infor8   	exceptionwarningr\   r]   r   r`   rZ   r   handle_requestupdate)rb   r   r   r   rU   r   r\   r]   auth_uri_callbackr5   welcome_urir   _urir6   r   r   r   r     sL   
	

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   closeP  s   zAuthCodeReceiver.closec                 C   s   | S rN   r   r   r   r   r   	__enter__U  s   zAuthCodeReceiver.__enter__c                 C   s   |    d S rN   )r   )rb   exc_typeexc_valexc_tbr   r   r   __exit__X  s   zAuthCodeReceiver.__exit__)NNrN   )NNNNNNNN)
rr   rs   rt   rz   r   r   r   r   r   r   r   r   r   r   r      s    
#
E
6r   __main__r:   )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 listauthorization_endpointr
   zhttp://{h}:{p})hr   )scoperedirect_urir   zA<a href='$auth_uri'>Sign In</a>, or <a href='$abort_uri'>Abort</az<html>Oh no. $error</html>zOh yeah. Got $coderU   )r   r   r]   r\   r   rU      )indentrN   )D__doc__loggingr   r   rw   stringr   r   r   http.serverr   r   urllib.parser   r   r   htmlr	   ImportErrorBaseHTTPServerurllibcgi	getLoggerrr   rW   r   r%   r/   r8   rF   rK   rM   rR   rS   objectru   r   r   argparsejsonoauth2r   basicConfigINFOArgumentParserArgumentDefaultsHelpFormatterr   parseradd_argumentint
parse_argsrp   endpointr   clientr   r   initiate_auth_code_flowr   r   r3   hostr   flowprintdumpsr   r   r   r   r   r   <module>   s   


% 
3


$