
    9iJ                        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	 ddl	m
Z
mZ ddlmZmZmZ ddlmZ  ej,                  e      Zd?d	Zd
 Zd Zd?dZd Zd Zd Zd Z  G d de      Z! G d de
e"      Z# G d de#      Z$ G d de"      Z%edk(  rddl&Z&ddl'Z'ddl(m)Z)  ejT                  ejV                          e&jX                  e&jZ                  e dz         xZ.Z/e.ja                  dd d!"       e.ja                  d#d$%       e.ja                  d&e1dd'(       e.ja                  d)e1d*d+(       e.ja                  d,d-d./       e.ja                  d0dd1/       e/je                         Z3 e)d2e3jh                  ie3jj                        Z6 e%e3jn                  3      5 Z8e6js                  e3jt                  re3jt                  jw                         ndd4jy                  e3jz                  e8j}                         5      6      Z? e@ e'j                  e8j                  e?d7   d8d9d:e3j                  e?d;   <      d=>             ddd       yy# e$ r  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 8w xY w# 1 sw Y   yxY w)@a$  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                     t        |       5 }|j                  |d      j                  d      cd d d        S # 1 sw Y   y xY w)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   receivers      J/var/www/html/venv/lib/python3.12/site-packages/msal/oauth2cli/authcode.pyobtain_auth_coder      sG    	{	+ x))" *  c&k  s	   "9Ac                  L   	 t        d      5 } | j                         D ]B  }|j                  dd      d   j                         }|j                         dk7  s: d d d        y 	 d d d        t
        j                  j                  d      S # 1 sw Y   (xY w# t        $ r Y 6w xY w)Nz/proc/1/cgroup:   /Tz/.dockerenv)open	readlinessplitstripIOErrorospathexists)flinecgroup_paths      r   _is_inside_dockerr&   *   s    	"# 	 q   "jja0399;$$&#-	  	  	  77>>-((	  	   s;   B A
BBB "B$B BB 	B#"B#c                      dd l } | j                         }t        |d|d         j                         }t        |d|d         j                         }|dk(  xr d|v S )Nr   systemreleaser   linux	microsoft)platformunamegetattrlower)r,   r-   platform_namer)   s       r   is_wslr1   8   s^    
 NNEE8U1X6<<>MeYa1779GG#>w(>>    c                    ddl }|r!|j                  |      j                  |       }n|j                  |       }|s:t               r0	 ddl}|j                  ddddj                  |       g      }|dk(  }|S |S # t        $ r Y |S w xY w)zJBrowse uri with named browser. Default browser is customizable by $BROWSERr   Nzpowershell.exez
-NoProfilez-CommandzStart-Process "{}")
webbrowserr   r   r1   
subprocesscallformatFileNotFoundError)r   browser_namer4   browser_openedr5   	exit_codes         r   _browser<   D   s    #5::8D $2 fh	 #!<=Q=X=XYa=bceI&!^N > ! 		s   -A7 7	BBc           	          | j                         D ci c]+  \  }}|t        |t              rt        |      dk(  r|d   n|- c}}S c c}}w )z;Flatten parse_qs()'s single-item lists into the item itself   r   )items
isinstancelistlen)qskvs      r   _qs2kvrF   [   sL     HHJ Aq z!T*s1v{qtA      s   0Ac                 $    | j                  d      S )N<)
startswithtexts    r   _is_htmlrL   a   s    ??3r2   c                 h    | j                         D ci c]  \  }}|t        |       c}}S c c}}w N)r?   r	   )key_value_pairsrD   rE   s      r   _escaperP   e   s+    %4%:%:%<=TQAvayL===s   .c                 \    t        | t              r| j                         st        |       S | S rN   )r@   strisprintablereprrJ   s    r   	_printifyrU   i   s%    #D#.t7G7G7I4:StSr2   c                        e Zd Zd ZddZd Zy)_AuthCodeHandlerc                    t        t        | j                        j                        }|j	                  d      s|j	                  d      rt        |      }t        j                  d|       | j                  j                  r:| j                  j                  |j	                  d      k7  r| j                  d       y d|v r| j                  j                  n| j                  j                  }t        |j                        rt        |      }n|}| j                   |j                   di |       || j                  _        y | j                  | j                  j$                         y )Nr   errorzGot auth response: %sstatezState mismatch )r   r   r!   queryr   rF   loggerdebugserver
auth_state_send_full_responsesuccess_templateerror_templaterL   templaterP   safe_substituteauth_responsewelcome_page)selfrC   rf   rd   	safe_datas        r   do_GETz_AuthCodeHandler.do_GETo   s    htyy)//066&>RVVG_"2JMLL0-@{{%%$++*@*@MDUDUV]D^*^ (()9: | !KK88)-)C)C H--. ' 6I -I(()A)A)A)NI)NO,9)$$T[[%=%=>r2   c                     | j                  |rdnd       t        |      rdnd}| j                  d|       | j                          | j                  j                  |j                  d             y )N   i  z	text/htmlz
text/plainzContent-typezutf-8)send_responserL   send_headerend_headerswfilewriteencode)rh   bodyis_okcontent_types       r   ra   z$_AuthCodeHandler._send_full_response   sX    %3S1&.tn{,6

W-.r2   c                 L    t        j                  |gt        t        |        y rN   )r]   r^   maprU   )rh   r7   argss      r   log_messagez_AuthCodeHandler.log_message   s    V3c)T23r2   N)T)__name__
__module____qualname__rj   ra   ry   r[   r2   r   rW   rW   n   s    ?0/4r2   rW   c                   $     e Zd Z fdZd Z xZS )_AuthCodeHttpServerc                     |\  }}|r$t         j                  dk(  s
t               rd| _        t	        t
        |   |g|i | y )Nwin32F)sysr,   r1   allow_reuse_addresssuperr~   __init__)rh   server_addressrx   kwargs_r   	__class__s         r   r   z_AuthCodeHttpServer.__init__   sB     4S\\W,
 (-D$!41.R4R6Rr2   c                     t        d      )Nz"Timeout. No auth response arrived.)RuntimeErrorrh   s    r   handle_timeoutz"_AuthCodeHttpServer.handle_timeout   s     ?@@r2   )rz   r{   r|   r   r   __classcell__)r   s   @r   r~   r~      s    SAr2   r~   c                   $    e Zd Zej                  Zy)_AuthCodeHttpServer6N)rz   r{   r|   socketAF_INET6address_familyr[   r2   r   r   r      s    __Nr2   r   c                   D    e Zd Zd	dZd Zd
dZ	 	 	 	 ddZd Zd Zd Z	y)r   Nc                     t               rdnd}t        |xs g       | _        d|v rt        nt        } |||xs dft
              | _        d| _        y)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~   rW   _server_closing)rh   r   scheduled_actionsaddressServers        r   r   zAuthCodeReceiver.__init__   sU       12) #)):)@b"A),%=P w	24DEr2   c                 4    | j                   j                  d   S )z*The port this server actually listening tor>   )r   r   r   s    r   get_portzAuthCodeReceiver.get_port   s     ||**1--r2   c                    i }t        j                  | j                  |f|      }d|_        |j	                          t        j
                         }|rt        j
                         |z
  |k  rn	 t        j                  d       |j                         sn| j                  rt        j
                         |z
  | j                  d   d   kD  r\| j                  j                  d      \  }} |        | j                  r+t        j
                         |z
  | j                  d   d   kD  r\|rt        j
                         |z
  |k  rn|xs d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.
        )targetrx   r   Tr>   r   N)
	threadingThread_get_auth_responsedaemonstarttimesleepis_aliver   pop)rh   timeoutr   resulttbeginr   callbacks           r   r   z"AuthCodeReceiver.get_auth_response   s   j **&6K				18tyy{U"W,dJJqM::<**		e+d.E.Ea.H.KK"5599!<8
 **		e+d.E.Ea.H.KK 29tyy{U"W,d ~r2   c
                    dj                  | j                               }
dj                  |
      }t        j                  d|       t	        |xs d      j                  ||      | j                  _        |rp|r|
n|}t        j                  d|z         d	}	 t        ||	
      }|s@|s6t        j                  dj                  ||| j                                      n ||       t	        |xs d      | j                  _        t	        |xs d      | j                  _        || j                  _        i | j                  _        || j                  _        | j"                  s>| j                  j%                          | j                  j                  rn| j"                  s>|j'                  | j                  j                         y #  t        j                  d       Y ;xY w)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)r9   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))r7   r   r]   r^   r   re   r   rg   infor<   	exceptionwarningrb   rc   r   rf   r`   r   handle_requestupdate)rh   r   r   r   rZ   r   rb   rc   auth_uri_callbackr9   welcome_urir   _urir:   s                 r   r   z#AuthCodeReceiver._get_auth_response  s   
 -33dmmo3F'..;.?	()4$,-=-C$D$T$T %U %4!"2;DKKDtKL"N>!(L!I
 "(NN	H IO%)7 IO IRS &d+(01A 2GF)H%&.~ 0NM'O#  '%'""'-- LL'')||)) -- 	dll001I>   !<=s   G	 	G#c                 F    d| _         | j                  j                          y)zGEither call this eventually; or use the entire class as context managerTN)r   r   server_closer   s    r   closezAuthCodeReceiver.closeP  s    !!#r2   c                     | S rN   r[   r   s    r   	__enter__zAuthCodeReceiver.__enter__U  s    r2   c                 $    | j                          y rN   )r   )rh   exc_typeexc_valexc_tbs       r   __exit__zAuthCodeReceiver.__exit__X  s    

r2   )NNrN   )NNNNNNNN)
rz   r{   r|   r   r   r   r   r   r   r   r[   r2   r   r   r      s9    !F.
CJ MQIM"42l$
r2   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 $coderZ   )r   r   rc   rb   r   rZ      )indentrN   )D__doc__loggingr    r   r   stringr   r   r   http.serverr   r   urllib.parser   r   r   htmlr	   ImportErrorBaseHTTPServerurllibcgi	getLoggerrz   r]   r   r&   r1   r<   rF   rL   rP   rU   rW   objectr~   r   r   argparsejsonoauth2r   basicConfigINFOArgumentParserArgumentDefaultsHelpFormatterr   parseradd_argumentint
parse_argsrx   endpointr   clientr   r   initiate_auth_code_flowr   r   r7   hostr   flowprintdumpsr   r   r[   r2   r   <module>r      s    	  
   >:: 
		8	$	)	?.  >T
"4- "4JA*f A(%. %nv nd zGgll+((( >>OOQ QA NN<P  R NN;%HNINN8#q7QNRNN;S";UNVNN8[7QNRNN9d1ANBD-t}}=t~~NF	tyy	) X--(,

$**""$)00499@Q@Q@S0T .  	jdjj33*%S71LLw- 4   	 # S
  A+ 	t
 s   I "B"I6!I32I36I?