
    h3                         d dl Z d dlZd dlZd dlmZ d dlmZmZmZ d dlZd dl	m
Z
 d dlmZ ddlmZmZmZmZmZ dZd	Zd
ZdZ G d d      Zy)    N)datetime)AnyDictOptional)verbose_logger)_get_httpx_client   )APIKeyExpiredErrorGetAccessTokenErrorGetAPIKeyErrorGetDeviceCodeErrorRefreshAPIKeyErrorzIv1.b507a08c87ecfe98z$https://github.com/login/device/codez+https://github.com/login/oauth/access_tokenz0https://api.github.com/copilot_internal/v2/tokenc                       e Zd ZddZdefdZdefdZdee   fdZde	ee
f   fdZddZdd	ee   de	eef   fd
Zde	eef   fdZdedefdZdefdZy)AuthenticatorreturnNc                    t        j                  dt         j                  j                  d            | _        t         j                  j                  | j                  t        j                  dd            | _        t         j                  j                  | j                  t        j                  dd            | _        | j                          y)zJInitialize the GitHub Copilot authenticator with configurable token paths.GITHUB_COPILOT_TOKEN_DIRz ~/.config/litellm/github_copilot GITHUB_COPILOT_ACCESS_TOKEN_FILEzaccess-tokenGITHUB_COPILOT_API_KEY_FILEzapi-key.jsonN)	osgetenvpath
expanduser	token_dirjoinaccess_token_fileapi_key_file_ensure_token_dirselfs    e/var/www/Befach/backend/env/lib/python3.12/site-packages/litellm/llms/github_copilot/authenticator.py__init__zAuthenticator.__init__   s     &GGAB
 "$NNII8.I"
 GGLLNNBII&C^T
 	     c           
         	 t        | j                  d      5 }|j                         j                         }|r|cddd       S 	 ddd       t        d      D ]c  }t        j                  d|dz    d       	 | j                         }	 t        | j                  d      5 }|j                  |       ddd       |c S  t        dd      # 1 sw Y   xY w# t        $ r t        j                  d       Y w xY w# 1 sw Y   KxY w# t        $ r t        j                  d	       Y nw xY w# t        t        t        f$ r2}t        j                  d
|dz    dt        |              Y d}~d}~ww xY w)z
        Login to Copilot with retry 3 times.

        Returns:
            str: The GitHub access token.

        Raises:
            GetAccessTokenError: If unable to obtain an access token after retries.
        rNz4No existing access token found or error reading file   z!Access token acquisition attempt r	   z/3wz!Error saving access token to filezFailed attempt z: z+Failed to get access token after 3 attempts  messagestatus_code)openr   readstripIOErrorr   warningrangedebug_loginwriteerrorr   r   r   str)r    faccess_tokenattemptes        r!   get_access_tokenzAuthenticator.get_access_token,   sf   	d,,c2 (a vvx~~/'( (( QxG  #DWq[MQS!TU
#{{}Nd44c: .a-. $#   "A
 	
/( (  	""F	. . N"(()LMN '(;=OP &&1RAx'PQs   C "C	C C 8D+	DC;1D9D+CC C87C8;D	 DD(%D+'D((D++E1?'E,,E1c                    	 t        | j                  d      5 }t        j                  |      }|j	                  dd      t        j                         j                         kD  r|j	                  d      cddd       S t        j                  d       t        dd	      # 1 sw Y   nxY wnp# t        $ r t        j                  d
       Y nPt        j                  t        f$ r+}t        j                  dt        |              Y d}~nd}~wt        $ r Y nw xY w	 | j                         }t        | j                  d      5 }t        j                   ||       ddd       n# 1 sw Y   nxY w|j	                  d      }|r|S t#        dd	      # t        $ r?}t        j$                  dt        |              t#        dt        |       d	      d}~wt&        $ r}t#        dt        |       d	      d}~ww xY w)z
        Get the API key, refreshing if necessary.

        Returns:
            str: The GitHub Copilot API key.

        Raises:
            GetAPIKeyError: If unable to obtain an API key.
        r%   
expires_atr   tokenNzAPI key expired, refreshingzAPI key expiredr(   r)   z+No API key file found or error opening filez!Error reading API key from file: r'   zAPI key response missing tokenzError saving API key to file: zFailed to save API key: i  zFailed to refresh API key: )r,   r   jsonloadgetr   now	timestampr   r0   r
   r/   JSONDecodeErrorKeyErrorr6   _refresh_api_keydumpr   r5   r   )r    r7   api_key_infor:   r>   s        r!   get_api_keyzAuthenticator.get_api_keyS   s   	d''- 	#yy|##L!4x||~7O7O7QQ'++G4	 	
 #**+HI, 1$' 	 	 	  	R""#PQ$$h/ 	Q""%Fs1vh#OPP! 			002Ld''- +		,*+ + + $$W-E$< #   	  #A#a&!JK 23q6(;  " 	 5c!fX> 	s   B, AB3	B, ="BB($B, ,DD$!D

DD&F E#	F #E,(F F 	G>:GG> G99G>c                 h   	 t        | j                  d      5 }t        j                  |      }|j	                  di       }|j	                  d      }|cddd       S # 1 sw Y   yxY w# t
        t        j                  t        f$ r+}t        j                  dt        |              Y d}~yd}~ww xY w)z
        Get the API endpoint from the api-key.json file.

        Returns:
            Optional[str]: The GitHub Copilot API endpoint, or None if not found.
        r%   	endpointsapiNz&Error reading API endpoint from file: )r,   r   r?   r@   rA   r/   rD   rE   r   r0   r6   )r    r7   rH   rK   api_endpointr:   s         r!   get_api_basezAuthenticator.get_api_base   s    	d''- $#yy|(,,["=	(}}U3#	$ $ $
 --x8 	""%KCPQF8#TU	s4   A( :A	A( A%!A( %A( (B1!B,,B1c                 >   | j                         }| j                  |      }d}t        |      D ]d  }	 t               }|j	                  t
        |      }|j                          |j                         }d|v r|c S t        j                  d|        f t        dd      # t        j                  $ r4}t        j                  d|dz    d| dt        |              Y d	}~d	}~wt        $ r+}t        j                  d
t        |              Y d	}~d	}~ww xY w)z
        Refresh the API key using the access token.

        Returns:
            Dict[str, Any]: The API key information including token and expiration.

        Raises:
            RefreshAPIKeyError: If unable to refresh the API key.
        r&   )headersr>   z API key response missing token: z'HTTP error refreshing API key (attempt r	   /z): Nz%Unexpected error refreshing API key: z/Failed to refresh API key after maximum retriesr(   r)   )r;   _get_github_headersr1   r   rA   GITHUB_API_KEY_URLraise_for_statusr?   r   r0   httpxHTTPStatusErrorr5   r6   	Exceptionr   )	r    r8   rP   max_retriesr9   sync_clientresponseresponse_jsonr:   s	            r!   rF   zAuthenticator._refresh_api_key   s"    ,,.**<8[)GW/1&??+=w?O))+ (m+(("**:=/J ** !E
 	
 (( $$=gai[+VYZ]^_Z`Yab   W$$'LSQRVH%UVVWs*   AB#<B##D6*C%%D1!DDc                     t         j                  j                  | j                        s"t        j                  | j                  d       yy)z"Ensure the token directory exists.T)exist_okN)r   r   existsr   makedirsr   s    r!   r   zAuthenticator._ensure_token_dir   s-    ww~~dnn-KK6 .r#   r8   c                 <    dddddd}|rd| |d<   d	|vrd|d	<   |S )
z
        Generate standard GitHub headers for API requests.

        Args:
            access_token: Optional access token to include in the headers.

        Returns:
            Dict[str, str]: Headers for GitHub API requests.
        zapplication/jsonzvscode/1.85.1zcopilot/1.155.0zGithubCopilot/1.155.0zgzip,deflate,br)acceptzeditor-versionzeditor-plugin-versionz
user-agentzaccept-encodingztoken authorizationzcontent-type )r    r8   rP   s      r!   rR   z!Authenticator._get_github_headers   sG     )-%610
 )/~'>GO$(&8GN#r#   c                    	 t               }|j                  t        | j                         t        dd      }|j                          |j                         g d}t        fd|D              s%t        j                  d        t        dd	      S # t        j                  $ r?}t        j                  d
t        |              t        dt        |       d	      d}~wt        j                  $ r?}t        j                  dt        |              t        dt        |       d	      d}~wt        $ r?}t        j                  dt        |              t        dt        |       d	      d}~ww xY w)z
        Get a device code for GitHub authentication.

        Returns:
            Dict[str, str]: Device code information.

        Raises:
            GetDeviceCodeError: If unable to get a device code.
        z	read:user)	client_idscoperP   r?   )device_code	user_codeverification_uric              3   &   K   | ]  }|v  
 y wNrc   ).0field	resp_jsons     r!   	<genexpr>z1Authenticator._get_device_code.<locals>.<genexpr>   s     Geu	)Gs   z"Response missing required fields: z Response missing required fields  r)   z HTTP error getting device code: zFailed to get device code: NError decoding JSON response: z'Failed to decode device code response: z&Unexpected error getting device code: )r   postGITHUB_DEVICE_CODE_URLrR   GITHUB_CLIENT_IDrT   r?   allr   r5   r   rU   rV   r6   rD   rW   )r    rY   resprequired_fieldsr:   ro   s        @r!   _get_device_codezAuthenticator._get_device_code   ss   $	+-K##&002#3kJ $ D
 !!#		INOGGG$$'I)%UV(> # 
 $$ 	  #CCF8!LM$5c!fX>  ## 	  #A#a&!JK$A#a&J   	  #I#a&!RS$5c!fX> 	s0   BB F,:C&&F<:D66F:E<<Frh   c           	         t               }d}t        |      D ]  }	 |j                  t        | j	                         t
        |dd      }|j                          |j                         }d|v rt        j                  d       |d   c S d|v r4|j                  d      dk(  r t        j                  d	|d
z    d| d       nt        j                  d|        t)        j*                  d        t#        dd      # t        j                  $ r?}t        j                  dt!        |              t#        dt!        |       d      d}~wt        j$                  $ r?}t        j                  dt!        |              t#        dt!        |       d      d}~wt&        $ r?}t        j                  dt!        |              t#        dt!        |       d      d}~ww xY w)a  
        Poll for an access token after user authentication.

        Args:
            device_code: The device code to use for polling.

        Returns:
            str: The access token.

        Raises:
            GetAccessTokenError: If unable to get an access token.
           z,urn:ietf:params:oauth:grant-type:device_code)re   rh   
grant_typerg   r8   zAuthentication successful!r5   authorization_pendingzAuthorization pending (attempt r	   rQ   )zUnexpected response: z%HTTP error polling for access token: zFailed to get access token: rq   r)   Nrr   z(Failed to decode access token response: z+Unexpected error polling for access token:    z2Timed out waiting for user to authorize the device)r   r1   rs   GITHUB_ACCESS_TOKEN_URLrR   ru   rT   r?   r   inforA   r2   r0   rU   rV   r5   r6   r   rD   rW   timesleep)r    rh   rY   max_attemptsr9   rw   ro   r:   s           r!   _poll_for_access_tokenz$Authenticator._poll_for_access_token  s    ()\*G,"''+ 446%5'2&T (  %%' IIK	!Y."''(DE$^44y(!g.2II"((9'!)Al^STU #**-B9++NO, JJqM_ +b "H
 	
/ (( $$'LSQRVH%UV):3q6(C #  '' $$'Ec!fX%NO)Fs1vhO #   $$A#a&J *:3q6(C # 	s7   A+C>
AC>>G&:EG&!:FG&':G!!G&c                     | j                         }|d   }|d   }|d   }t        d| d| dd       | j                  |      S )	a  
        Login to GitHub Copilot using device code flow.

        Returns:
            str: The GitHub access token.

        Raises:
            GetDeviceCodeError: If unable to get a device code.
            GetAccessTokenError: If unable to get an access token.
        rh   ri   rj   zPlease visit z and enter code z to authenticate.T)flush)ry   printr   )r    device_code_inforh   ri   rj   s        r!   r3   zAuthenticator._loginU  si      002&}5$[1	+,>?,--=i[HYZ 	
 **;77r#   )r   Nrl   )__name__
__module____qualname__r"   r6   r;   rI   r   rN   r   r   rF   r   rR   ry   r   r3   rc   r#   r!   r   r      s    ! %
# %
N2S 2hhsm "&
$sCx. &
P7
 cSVh 4.$sCx. .`D
# D
# D
L8 8r#   r   )r?   r   r   r   typingr   r   r   rU   litellm._loggingr   &litellm.llms.custom_httpx.http_handlerr   common_utilsr
   r   r   r   r   ru   rt   r   rS   r   rc   r#   r!   <module>r      sP     	   & &  + D  * ? G G S8 S8r#   