o
    :F¶d¸6  ã                   @   s|  d dl mZ d dlmZ d dlmZ d dlmZmZmZ d dlm	Z	 d dl
Z
d dlZd dlZd dlm  mZ d dl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mZmZmZ d d	lmZmZ d
ZdZ dZ!ej"j#ddj$eddej%dddej%dddej&ej'ej(dd„ ƒƒƒƒƒƒZ)d%dd„Z*d&dd„Z+G dd„ deƒZ,G dd „ d eƒZ-G d!d"„ d"e.ƒZ/d#d$„ Z0dS )'é    )Úprint_function)Ú	cli_setup)Úcli_util)ÚDEFAULT_KEY_NAMEÚPUBLIC_KEY_FILENAME_SUFFIXÚPRIVATE_KEY_FILENAME_SUFFIX)Úprompt_for_passphraseN)Úidentity)ÚurlparseÚparse_qsÚ	urlencode)ÚBaseHTTPRequestHandlerÚ
HTTPServeriõ  zBootstrap process canceled.z2https://login.{region}.{realm}/v1/oauth2/authorizeÚ	bootstrapa/  
Provides an interactive process to create a CLI config file using username / password based login through a browser.
Also handles generating API keys and uploading them to your Oracle Cloud Infrastructure account.

Note that port {port} must be available in order for this command to complete properly.©Úport)Úhelpz--profile-namez$Name of the profile you are creatingz--config-locationz&Path to the config for the new profilec                 C   s  | j d r
| j d nd}t|d}|j}|j}|j}|j}|j}	|j}
|j}t	j
j ||¡}tjd|i|d}| |	¡}|jD ]
}|jrI|j} nq?tjd|i|d}tj ¡ }tj|d d¡|_z| |
|¡}W nr t	jjyÜ } zd|jdkrÐ|jdkrÐ| |
¡}t  d	¡ t  d
¡ d}|jD ]}t  dj!||j|j"dt#j$¡ |d7 }q’tj%ddd}|s»t  t&¡ t# 'd¡ | (|
|¡ t  d !|¡¡ | |
|¡ n|‚W Y d }~nd }~ww t  d !|¡¡ |rít)j* +|¡nd }t,|||ddd\}}t  d !|¡¡ t  dj!||d¡ d S )NÚregionÚ )r   )Úsigner)Ú
public_keyúUTF-8i™  ZApiKeyLimitExceededz4ApiKey limit has been reached for this user account.z>The following API keys are currently enabled for this account:é   zH	Key [{index}]: Fingerprint: {fingerprint}, Time Created: {time_created})ÚindexÚfingerprintÚtime_createdz|Enter the fingerprint of the API key to delete to make space for the new key (leave empty to skip deletion and exit command)T)ÚtextZconfirmation_promptr   z$Deleted Api key with fingerprint: {}z)Uploaded new API key with fingerprint: {}F)Úprofile_nameÚconfigÚpersist_tokenr   zConfig written to: {}zœ
    Try out your newly registered credentials with the following example command:

    oci iam region list --config-file {config_file} --profile {profile}
)Úconfig_fileZprofile)-ÚobjÚcreate_user_sessionr   Úprivate_keyr   ÚtokenÚtenancy_ocidÚ	user_ocidr   ÚociZauthZsignersZSecurityTokenSignerr	   ZIdentityClientZlist_region_subscriptionsÚdataZis_home_regionZregion_nameZmodelsZCreateApiKeyDetailsr   Zserialize_keyÚdecodeÚkeyZupload_api_keyÚ
exceptionsZServiceErrorÚstatusÚcodeZlist_api_keysÚclickÚechoÚformatr   ÚsysÚstderrÚpromptÚ"BOOTSTRAP_PROCESS_CANCELED_MESSAGEÚexitZdelete_api_keyÚosÚpathÚ
expanduserÚpersist_user_session)Úctxr   Úconfig_locationZregion_paramÚuser_sessionr   r#   r   r$   r%   r&   r   r   ZclientÚresultÚrZhome_regionZcreate_api_key_detailsÚeÚcountZdelete_thumbprintZ
config_loc© rA   ú?usr/lib/python3.10/site-packages/oci_cli/cli_setup_bootstrap.pyÚbootstrap_oci_cli    sn   


þ




ýü


þ€êürC   r   c              
   C   s   | dkrt  ¡ } zdtf}t|tƒ}W n" ty5 } z|jtjkr/t 	dj
td¡ t d¡ |‚d }~ww t ¡ }| ¡ }t  |¡}t |¡}|}	|	 d¡}
t |
¡ d¡}|}dddt ¡ d	|d
 
t¡dœ}|rn||d< | tjv rxtj|  } t | ¡r‹tj
| tjtj|   d}nt 	d 
| tj¡¡ t d¡ t|ƒ}dj
||d}z%t  !|¡r½t 	d¡ t 	d¡ t 	d| ¡ nt 	d¡ t 	d| ¡ W n# t j"yí } zt 	dj
t#|ƒd¡ t d¡ W Y d }~nd }~ww | $¡ }t 	d¡ t%j|dd}|d }|d }t&||| ||||ƒS )Nr   zKCould not complete bootstrap process because port {port} is already in use.r   r   r   ZloginZiaas_consoleztoken id_tokenZopenidzhttp://localhost:{})ÚactionZ	client_idZresponse_typeZnonceÚscoper   Zredirect_uriZtenant)r   Úrealmz6Error: {} is not a valid region. Valid regions are 
{}z!{console_auth_url}?{query_string})Zconsole_auth_urlÚquery_stringz;    Please switch to newly opened browser window to log in!zL    You can also open the following URL in a web browser window to continue:z%sz?    Open the following URL in a web browser window to continue:zeCould not launch web browser to complete login process, exiting bootstrap command. Error: {exc_info}.)Úexc_infoz-    Completed browser authentication process!F)ZverifyÚsub)'r   Zprompt_for_regionÚBOOTSTRAP_SERVICE_PORTÚStoppableHttpServerÚStoppableHttpRequestHandlerÚOSErrorÚerrnoZ
EADDRINUSEr.   r/   r0   r1   r5   r   Zgenerate_keyr   Zpublic_key_to_fingerprintZto_jwkÚencodeÚbase64Úurlsafe_b64encoder)   ÚuuidZuuid4ÚregionsZREGIONS_SHORT_NAMESZ	is_regionÚCONSOLE_AUTH_URL_FORMATZREALMSZREGION_REALMSZREGIONSr   Ú
webbrowserZopen_newÚErrorÚstrÚserve_foreverÚjwtÚUserSession)r   Ztenancy_nameZserver_addressZhttpdr?   r#   r   r   r*   Zjwk_contentZbytes_jwk_contentZb64_jwk_contentZpublic_key_jwkÚqueryZconsole_urlrG   Úurlr$   Z
token_datar&   r%   rA   rA   rB   r"   q   s„   ÿ
€ø


ù



ÿ
þ



€ÿ€ü
r"   Fc                 C   s¾  |st  ¡ \}}|r|}nt j}|st t¡ t d¡ tj	 
tj	 t j|¡¡}	tj	 |	¡s3t |	¡ tj	 |	tt ¡}
|sGtj	 |	tt ¡}t  |
| jdd¡sZt t¡ t d¡ d }|sb|re|retƒ }|s{t  || j|dd¡s{t t¡ t d¡ |r¤tj	 |	d¡}t|dƒ}| | j¡ W d   ƒ n1 sšw   Y  t |¡ t  ||¡ d }|r±| j}|r¾|r¾tjddds¾d }t j||| j |sÌtj	 
|¡nd| j!| j"|||r×|nd d		 ||fS )
Nr   Tr$   Úwz‹Do you want to write your passphrase to the config file? (If not, you will need to enter it when prompted each time you run an oci command)F)ÚdefaultZUpdate_private_key_path)	ÚfilenameZuser_idr   Zkey_fileZtenancyr   Zpass_phraser   Úsecurity_token_file)#r   Zprompt_session_for_profileZDEFAULT_CONFIG_LOCATIONr.   r/   r4   r1   r5   r6   r7   ÚabspathÚjoinZDEFAULT_TOKEN_DIRECTORYÚexistsr   Zcreate_directoryr   r   r   Zwrite_public_key_to_filer   r   Zwrite_private_key_to_filer#   ÚopenÚwriter$   Z"apply_user_only_access_permissionsZremove_profile_from_configr&   ZconfirmZwrite_configr   r%   r   )r<   r   r   Zuse_passphraser   r   Zsession_authZpersist_only_public_keyr;   Zsession_auth_locationZpublic_key_file_pathZprivate_key_file_pathZkey_passphraseZtoken_locationr`   ZuserIdrA   rA   rB   r9   É   s`   






ÿ

÷r9   c                   @   s    e Zd ZdZdd„ Zdd„ ZdS )rL   z5http request handler with abilitiy to stop the serverc                 G   s   d S ©NrA   )Úselfr0   ÚargsrA   rA   rB   Úlog_message  s   z'StoppableHttpRequestHandler.log_messagec                 C   s–   |   d¡ |  ¡  | jdkr-d}z	| j |¡ W dS  ty,   | j t|dƒ¡ Y dS w tt| jƒj	ƒ}d|v rI|d d }|| j
_d| j
_dS dS )	z1send 200 OK response, and set server.stop to TrueéÈ   ú/a
  
            <script type='text/javascript'>
                hash = window.location.hash

                // remove leading '#' so that python can detect it
                if (hash[0] === '#') {
                    hash = hash.substr(1)
                }

                console.log(hash)

                function reqListener () {
                    console.log(this.responseText);
                    document.write('Authorization completed! Please close this window and return to your terminal to finish the bootstrap process.')
                }

                var oReq = new XMLHttpRequest();
                oReq.addEventListener("load", reqListener);
                oReq.open("GET", "/token?" + hash);
                oReq.send();
            </script>
            r   Úsecurity_tokenr   TN)Zsend_responseZend_headersr7   Zwfilere   Ú	TypeErrorÚbytesr   r
   r[   ÚserverÚ	ret_valueÚstop)rg   Z
javascriptZquery_componentsrl   rA   rA   rB   Údo_GET  s   

ÿýz"StoppableHttpRequestHandler.do_GETN)Ú__name__Ú
__module__Ú__qualname__Ú__doc__ri   rr   rA   rA   rA   rB   rL     s    rL   c                   @   s   e Zd ZdZdd„ ZdS )rK   z)http server that reacts to self.stop flagc                 C   s.   d| _ d| _| j s|  ¡  | j r	|  ¡  | jS )z+Handle one request at a time until stopped.FN)rq   rp   Zhandle_requestZserver_close)rg   rA   rA   rB   rX   =  s   ÿz!StoppableHttpServer.serve_foreverN)rs   rt   ru   rv   rX   rA   rA   rA   rB   rK   :  s    rK   c                   @   s   e Zd Zdd„ ZdS )rZ   c                 C   s.   || _ || _|| _|| _|| _|| _|| _d S rf   )r&   r%   r   r$   r   r#   r   )rg   r&   r%   r   r$   r   r#   r   rA   rA   rB   Ú__init__L  s   
zUserSession.__init__N)rs   rt   ru   rw   rA   rA   rA   rB   rZ   K  s    rZ   c                 C   s<   t j | ¡}t j |¡rt d¡‚t j |¡rt d¡‚|S )Nz6Token file location must be a filename not a directoryz(Token file location cannot already exist)r6   r7   r8   Úisdirr.   ZBadParameterrc   )r_   Zfilename_expandedrA   rA   rB   Úprocess_security_tokennameV  s   

ry   )r   N)NNFFFFF)1Ú
__future__r   Úoci_clir   r   Zoci_cli.cli_setupr   r   r   r   rP   r.   rN   Zoci._vendor.jwtÚ_vendorrY   r'   Zoci.regionsrS   r6   r1   rR   rU   r	   Úurllib.parser
   r   r   Zhttp.serverr   r   rJ   r4   rT   Zsetup_groupÚcommandr0   ÚoptionÚhelp_optionZpass_contextZwrap_exceptionsrC   r"   r9   rL   rK   ÚobjectrZ   ry   rA   rA   rA   rB   Ú<module>   sH   
ü
G
XB/