
    2iX                        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
	 ddlmZmZ ddlmZmZmZ ddlmZ  ej0                  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jX                  ejZ                          e(j\                  e(j^                  e dz         xZ0Z1e0je                  d d!d"#       e0je                  d$d%&       e0je                  d'e3dd()       e0je                  d*e3d+d,)       e0je                  d-d.d/0       e0je                  d1dd20       e1ji                         Z5 e+d3e5jl                  ie5jn                        Z8 e'e5jr                  4      5 Z:e8jw                  e5jx                  re5jx                  j{                         ndd5j}                  e5j~                  e:j                         6      7      ZA eB e)j                  e:j                  eAd8   d9d:d;e5j                  eAd<   =      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)Aa$  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                     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      M/var/www/html/qr/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_wslr2   9   s^    
 NNEE8U1X6<<>MeYa1779GG#>w(>>    c                 V    	 t               }|j                  dvr!t        j                  d|j                         y	 t         fddD              rt        j                  d       ydd	l}|r!|j                  |      j                         }n|j                         }|sCt               r9dd	l
}	 |j                  d
 g      }|dk(  }|s	 |j                  d g      }|dv }|S |S # t        $ r t        j                  d        Y yw xY w# t        $ r Y Nw xY w# t        $ r Y |S w xY w)zJBrowse uri with named browser. Default browser is customizable by $BROWSER)httphttpsz"Invalid URI scheme for browser: %sFzInvalid URI: %sc              3   &   K   | ]  }|v  
 y wN ).0cr   s     r   	<genexpr>z_browse.<locals>.<genexpr>O   s     
+Q1=
+s   z
	zInvalid characters in URIr   Nwslviewzexplorer.exe)r      )r   schemeloggerwarning
ValueErrorany
webbrowserr   r   r2   
subprocesscallFileNotFoundError)r   browser_name
parsed_urirD   browser_openedrE   	exit_codes   `      r   _browserL   E   s?   h'
$55NN?ARARS 6 
+(
++23#5::8D $2 fh	"H(=>I&!^N  'OO^X,FG	!*f!4 >?  ((3* ! 		 % s5   9C' 1D D 'D	D		DD	D('D(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 itselfr>   r   )items
isinstancelistlen)qskvs      r   _qs2kvrU   n   sL     HHJ Aq z!T*s1v{qtA      s   0Ac                 $    | j                  d      S )N<)
startswithtexts    r   _is_htmlr[   t   s    ??3r3   c                 h    | j                         D ci c]  \  }}|t        |       c}}S c c}}w r8   )rN   r
   )key_value_pairsrS   rT   s      r   _escaper^   x   s+    %4%:%:%<=TQAvayL===s   .c                 \    t        | t              r| j                         st        |       S | S r8   )rO   strisprintablereprrY   s    r   	_printifyrc   {   s%    #D#.t7G7G7I4:StSr3   c                   ,    e Zd Zd Zd Zd ZddZd Zy)_AuthCodeHandlerc                    t        t        | j                        j                        }|j	                  dd g      d   }|j	                  dd g      d   }|dk(  r&| j                  | j                  j                         y |dk(  r| j                  dd       y |r| j                  d	d       y | j                  d
d       y )N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)selfrR   welcome_paramerror_params       r   do_GETz_AuthCodeHandler.do_GET   s    htyy)//0y4&1!4ffWtf-a0F"$$T[[%=%=>G#$$%=U$K$$R %  $$q % r3   c                 X   t        | j                  j                  dd            }| j                  j	                  |      j                  d      }t        |      }|j                  d      s|j                  d      r| j                  t        |             y | j                  dd       y )	NzContent-Lengthr   utf-8r   rh   zInvalid POST requestFrk   )
intheadersr   rfilereaddecoder   _process_auth_responserU   rn   )rq   content_length	post_datarR   s       r   do_POSTz_AuthCodeHandler.do_POST   s     T\\--.>BCJJOON3::7C	i 66&>RVVG_''r
3$$%;5$Ir3   c                    t         j                  d|       | j                  j                  r<| j                  j                  |j	                  d      k7  r| j                  dd       yd|v r| j                  j                  n| j                  j                  }t        |j                        rt        |      }n|}t        t        |      }| j                   |j                  di |       || j                  _        y)	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.Frk   r   Nr9   )r@   debugro   
auth_stater   rn   success_templateerror_templater[   templater^   r   r`   safe_substituteauth_response)rq   r   r   	safe_datafilled_datas        r   r|   z'_AuthCodeHandler._process_auth_response   s    ,m<;;!!dkk&<&<@Q@QRY@Z&Z $$PX] % _ ]* 44040J0J ))*#M2	)	%c95K$$%=X%=%=%L%LM(5DKK%r3   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-typerv   )send_responser[   send_headerend_headerswfilewriteencode)rq   bodyrl   content_types       r   rn   z$_AuthCodeHandler._send_full_response   sX    %3S1&.tn{,6

W-.r3   c                 L    t        j                  |gt        t        |        y r8   )r@   r   maprc   )rq   formatargss      r   log_messagez_AuthCodeHandler.log_message   s    V3c)T23r3   N)T)__name__
__module____qualname__rt   r   r|   rn   r   r9   r3   r   re   re      s    *	J6&/4r3   re   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-   r2   allow_reuse_addresssuperr   __init__)rq   server_addressr   kwargs_r   	__class__s         r   r   z_AuthCodeHttpServer.__init__   sB     4S\\W,
 (-D$!41.R4R6Rr3   c                     t        d      )Nz"Timeout. No auth response arrived.)RuntimeErrorrq   s    r   handle_timeoutz"_AuthCodeHttpServer.handle_timeout   s     ?@@r3   )r   r   r   r   r   __classcell__)r   s   @r   r   r      s    SAr3   r   c                   $    e Zd Zej                  Zy)_AuthCodeHttpServer6N)r   r   r   socketAF_INET6address_familyr9   r3   r   r   r      s    __Nr3   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   re   _server_closing)rq   r   scheduled_actionsaddressServers        r   r   zAuthCodeReceiver.__init__   sU       12) #)):)@b"A),%=P w	24DEr3   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--r3   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.
            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   Tr>   r   N)
	threadingThread_get_auth_responsedaemonstarttimesleepis_aliver   pop)rq   timeoutr   resulttbeginr   callbacks           r   r   z"AuthCodeReceiver.get_auth_response  s   l **&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 ~r3   c
                 b   dj                  | j                               }
dj                  |
      }t        j                  d|       |r>t	        t        |      j                        }|j                  dd g      d   dk(  sJ d	       t        |xs d
      j                  ||      | j                  _        |rs|r|
dz   n|}t        j                  d|z         d}	 t        ||	      }|s@|s6t        j                  dj                  ||| j                                      n ||       d}t        |xs d|z         | j                  _        t        |xs d|z         | j                  _        || j                  _        i | j                  _        || j                  _        | j*                  s>| j                  j-                          | j                  j&                  rn| j*                  s>|j/                  | j                  j&                         y #  t        j                  d       Y CxY w)Nzhttp://localhost:{p})pz{loc}?error=abort)loczAbort by visit %sresponse_moder   	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)rH   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   r@   r   r   r   rm   r   r   r   r   rp   inforL   	exceptionrA   r   r   r   r   r   r   handle_requestupdate)rq   r   r   r   r   r   r   r   auth_uri_callbackrH   netlocr   params_urirJ   recommendations                   r   r   z#AuthCodeReceiver._get_auth_responseH  s   
 (...A'..6.:	()4 hx0667F::ov6q9[H KJKH %--=-C$D$T$T %U %4!1AF_,xDKKDtKL"N>!(L!I
 "(NN	H IO%)7 IO IRS &d+{(01A 2~lo}})%&.~ 0d SUcc	'e#  '%'""'-- LL'')||)) -- 	dll001Q>   !<=s   H H.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.close  s    !!#r3   c                     | S r8   r9   r   s    r   	__enter__zAuthCodeReceiver.__enter__  s    r3   c                 $    | j                          y r8   )r   )rq   exc_typeexc_valexc_tbs       r   __exit__zAuthCodeReceiver.__exit__  s    

r3   )NNr8   )NNNNNNNN)
r   r   r   r   r   r   r   r   r   r   r9   r3   r   r   r      s:    !F.
DL MQIM"B2H$
r3   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   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 $coder   )r   r   r   r   r   r      )indentr8   )F__doc__collectionsr   loggingr!   r   r   stringr   r   r   http.serverr   r   urllib.parser   r   r	   htmlr
   ImportErrorBaseHTTPServerurllibcgi	getLoggerr   r@   r   r'   r2   rL   rU   r[   r^   rc   re   objectr   r   r   argparsejsonoauth2r   basicConfigINFOArgumentParserArgumentDefaultsHelpFormatterr   parseradd_argumentrw   
parse_argsr   endpointr   clientr   r   initiate_auth_code_flowr   r   r   hostr   flowprintdumpsr   r   r9   r3   r   <module>r     s   $  	  
   >:: 
		8	$	)	?&R  >T>4- >4BA*f A(%. %}v }B 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*%T71LLw- 4   	 # I  A+ 	j s   I (B"I<!I98I9<J