o
    ÙKÕiÌ=  ã                   @   s\  d dl Z d dlZd dlZd dl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mZmZ d dlmZmZ d dlmZ d dlmZ eƒ Zdedefd	d
„Ze eeƒ¡ZG dd„ dejƒZG dd„ dej ƒZ!dd„ Z"	dJdeeef deeef dedeeef fdd„Z#dg fdedee defdd„Z$	dKdede%de%de%fdd„Z&d eeef d!ede%fd"d#„Z'g d$¢Z(e(fd%ee defd&d'„Z)d(ee de%de%fd)d*„Z*d+ede j fd,d-„Z+d.edefd/d0„Z,d1d2„ Z-d3d4„ Z.d5d6d7d8d9d:œZ/d;edefd<d=„Z0d>ee dee fd?d@„Z1de%fdAdB„Z2dCedDedefdEdF„Z3dGee fdHdI„Z4dS )Lé    N©Úwraps)ÚAnyÚDictÚListÚOptionalÚUnion)Ú
exceptionsÚmessages)ÚCONFIG_FIELD_ENVVAR_ALLOWLIST)ÚMessagingOperationsÚnameÚreturnc                 C   s(   | dkrdS |   d¡}d|d< d |¡S )z1Replace the name of the root logger from __name__Ú Ú.Ú	ubuntupror   )ÚsplitÚjoin)r   Únames© r   ú//usr/lib/python3/dist-packages/uaclient/util.pyÚreplace_top_level_logger_name   s
   

r   c                       s    e Zd ZdZ‡ fdd„Z‡  ZS )ÚDatetimeAwareJSONEncoderzBA json.JSONEncoder subclass that writes out isoformat'd datetimes.c                    s    t |tjƒr
| ¡ S tƒ  |¡S ©N)Ú
isinstanceÚdatetimeÚ	isoformatÚsuperÚdefault)ÚselfÚo©Ú	__class__r   r   r   "   s   z DatetimeAwareJSONEncoder.default)Ú__name__Ú
__module__Ú__qualname__Ú__doc__r   Ú__classcell__r   r   r!   r   r      s    r   c                       s,   e Zd ZdZ‡ fdd„Zedd„ ƒZ‡  ZS )ÚDatetimeAwareJSONDecodera,  
    A JSONDecoder that parses some ISO datetime strings to datetime objects.

    Important note: the "some" is because we seem to only be able extend
    Python's json library in a way that lets us convert string values within
    JSON objects (e.g. '{"lastModified": "2019-07-25T14:35:51"}'). Strings
    outside of JSON objects (e.g. '"2019-07-25T14:35:51"') will not be passed
    through our decoder.

    (N.B. This will override any object_hook specified using arguments to it,
    or used in load or loads calls that specify this as the cls.)
    c                    s.   d|v r	|  d¡ tƒ j|d| ji|¤Ž d S )NÚobject_hook)Úpopr   Ú__init__r)   )r   ÚargsÚkwargsr!   r   r   r+   6   s   
z!DatetimeAwareJSONDecoder.__init__c              	   C   sL   |   ¡ D ]\}}t|tƒr#zt|ƒ}W n ty   |}Y nw || |< q| S r   )Úitemsr   ÚstrÚparse_rfc3339_dateÚ
ValueError)r    ÚkeyÚvalueÚ	new_valuer   r   r   r)   ;   s   
ÿþ€z$DatetimeAwareJSONDecoder.object_hook)r#   r$   r%   r&   r+   Ústaticmethodr)   r'   r   r   r!   r   r(   (   s
    r(   c                    s   ‡ ‡fdd„}|S )aÖ  Decorator to retry on exception for retry_sleeps.

    @param retry_sleeps: List of sleep lengths to apply between
       retries. Specifying a list of [0.5, 1] tells subp to retry twice
       on failure; sleeping half a second before the first retry and 1 second
       before the second retry.
    @param exception: The exception class to catch and retry for the provided
       retry_sleeps. Any other exception types will not be caught by the
       decorator.
    c                    s   t ˆ ƒ‡‡ ‡fdd„ƒ}|S )Nc               
      sp   ˆ  ¡ }	 zˆ| i |¤ŽW S  ˆ y6 } z|s|‚t dt|ƒt|ƒ¡ t | d¡¡ W Y d }~nd }~ww q)NTz%s: Retrying %d more times.r   )ÚcopyÚLOGÚdebugr/   ÚlenÚtimeÚsleepr*   )r,   r-   ÚsleepsÚe)Ú	exceptionÚfÚretry_sleepsr   r   Ú	decoratorW   s   ÿ€úýz)retry.<locals>.wrapper.<locals>.decoratorr   )r?   rA   ©r>   r@   )r?   r   ÚwrapperV   s   zretry.<locals>.wrapperr   )r>   r@   rC   r   rB   r   ÚretryJ   s   rD   r   Ú	orig_dictÚnew_dictÚpathc           	      C   sº   i }|   ¡ D ]C\}}| |t¡}|s|n|d | }t|tƒr8||v r3t||| |d�}|r2|||< qt||< q||krIt d|t|ƒ¡ |||< q|  ¡ D ]\}}|| vrZ|||< qN|S )z<Return a dictionary of delta between orig_dict and new_dict.r   )rG   z'Contract value for '%s' changed to '%s')	r.   ÚgetÚDROPPED_KEYr   ÚdictÚget_dict_deltasr7   r8   r/   )	rE   rF   rG   Údeltasr2   r3   r4   Úkey_pathÚ	sub_deltar   r   r   rK   j   s4   

ÿ€
ý€€rK   ÚmsgÚvalid_choicesc                 C   sf   ddl m} | ¡ }d}d |d dd„ |D ƒ¡¡}	 | | ¡ td	ƒ ¡ }||v r-	 |S | |¡ q)
aG  Interactive prompt message, returning a valid choice from msg.

    Expects a structured msg which designates choices with square brackets []
    around the characters which indicate a valid choice.

    Uppercase and lowercase responses are allowed. Loop on invalid choices.

    :return: Valid response character chosen.
    r   )Úevent_loggerr   z{} is not one of: {}z, c                 S   s   g | ]}|  ¡ ‘qS r   )Úupper)Ú.0Úchoicer   r   r   Ú
<listcomp>—   s    z"prompt_choices.<locals>.<listcomp>Tz> )ÚuaclientrQ   Úget_event_loggerÚformatr   ÚinfoÚinputÚlower)rO   rP   rQ   Úeventr3   Ú	error_msgr   r   r   Úprompt_choicesˆ   s   
ÿ

ÿûr^   FÚ
assume_yesr   c                 C   s>   |rdS | s	t j} t| ƒ ¡  ¡ }|dkr|S |dv rdS dS )a�  
    Display a confirmation prompt, returning a bool indicating the response

    :param msg: String custom prompt text to emit from input call.
    :param assume_yes: Boolean set True to skip confirmation input and return
        True.
    :param default: Boolean to return when user doesn't enter any text

    This function will only prompt a single time, and defaults to "no" (i.e. it
    returns False).
    Tr   )ÚyÚyesF)r
   ÚPROMPT_YES_NOrZ   r[   Ústrip)rO   r_   r   r3   r   r   r   Úprompt_for_confirmation¢   s   rd   ÚconfigÚpath_to_valuec                 C   s„   | }i }|  d¡}|d }|D ]}||krd}t|tƒr#| ||¡}q dS t|ƒ}| ¡ dkr2dS | ¡ dkr:dS tj|d|d�‚)	aJ  Check if value parameter can be translated into a boolean 'True' value.

    @param config: A config dict representing
                   /etc/ubuntu-advantange/uaclient.conf
    @param path_to_value: The path from where the value parameter was
                          extracted.
    @return: A boolean value indicating if the value paramater corresponds
             to a 'True' boolean value.
    @raises exceptions.UbuntuProError when the value provide by the
            path_to_value parameter can not be translated into either
            a 'False' or 'True' boolean value.
    r   éÿÿÿÿÚfalseFÚtrueTzboolean string: true or false)rf   Úexpected_valuer3   )r   r   rJ   rH   r/   r[   r	   ÚInvalidBooleanConfigValue)re   rf   r3   Údefault_valueÚpathsÚ
leaf_valuer2   Ú	value_strr   r   r   Úis_config_value_true¼   s(   

ýrp   )z(Bearer )[^\']+z(\'attach\', \')[^\']+z(\'machineToken\': \')[^\']+ú(\'token\': \')[^\']+z((\'X-aws-ec2-metadata-token\': \')[^\']+z*(.*\[PUT\] response.*api/token,.*data: ).*z(https://bearer:)[^\@]+z1(/snap/bin/canonical-livepatch\s+enable\s+)[^\s]+z>(Contract\s+value\s+for\s+'resourceToken'\s+changed\s+to\s+).*z(\'resourceToken\': \')[^\']+z(\'contractToken\': \')[^\']+zF(https://contracts.canonical.com/v1/resources/livepatch\?token=)[^\s]+z(\"identityToken\": \")[^\"]+zT(response:\s+http://metadata/computeMetadata/v1/instance/service-accounts.*data: ).*rq   z(\'userCode\': \')[^\']+z(\'magic_token=)[^\']+z(--registration-key=\")[^\"]+z(--registration-key=\')[^\']+z(--registration-key=)[^ ]+z(--registration-key \")[^\"]+z(--registration-key \')[^\']+z(--registration-key )[^\s]+z(-p \")[^\"]+z(-p \')[^\']+z(-p )[^\s]+Úredact_regexsc                 C   s    | }|D ]	}t  |d|¡}q|S )z4Redact known sensitive information from log content.z\g<1><REDACTED>)ÚreÚsub)Úlogrr   Úredacted_logÚredact_regexr   r   r   Úredact_sensitive_logs  s   rx   Úmsg_opsc                 C   sN   | sdS | D ]}t |tƒrt|ƒ q|\}}||d< |di |¤Žs$ dS qdS )ah  Emit messages to the console for user interaction

    :param msg_op: A list of strings or tuples. Any string items are printed.
        Any tuples will contain a callable and a dict of args to pass to the
        callable. Callables are expected to return True on success and
        False upon failure.

    :return: True upon success, False on failure.
    Tr_   FNr   )r   r/   Úprint)ry   r_   Úmsg_opÚfunctorr,   r   r   r   Úhandle_message_operations  s   

ÿr}   Údt_strc                 C   sD   t  dd| ¡}t  dd|¡}| dd¡}t  dd|¡}tj |d	¡S )
aT  
    Parse a datestring in rfc3339 format. Originally written for compatibility
    with golang's time.MarshalJSON function. Also handles output of pythons
    isoformat datetime method.

    This drops subseconds.

    :param dt_str: a date string in rfc3339 format

    :return: datetime.datetime object of time represented by dt_str
    z(\d{2}:\d{2}:\d{2})\.\d+z\g<1>z(\d{2}:\d{2}:\d{2})$z\g<1>ZÚZz+00:00z(-|\+)(\d{2}):(\d{2})$z\g<1>\g<2>\g<3>z%Y-%m-%dT%H:%M:%S%z)rs   rt   Úreplacer   Ústrptime)r~   Údt_str_without_subsecondsÚdt_str_with_zÚdt_str_without_zÚdt_str_with_pythonish_tzr   r   r   r0   &  s   ÿÿ	ÿÿr0   Úmessagec                 C   s`   t jjdu sdt jj ¡ vr.|  dd¡} |  tjd d¡} |  tjd d¡} |  dd¡ 	¡ } | S )	z}
    Verify if the system can output unicode characters and if not,
    remove those characters from the message string.
    NzUTF-8u   â€”ú-ú r   ÚasciiÚignore)
ÚsysÚstdoutÚencodingrR   r€   r
   ÚOKGREEN_CHECKÚFAIL_XÚencodeÚdecode)r†   r   r   r   Úhandle_unicode_characters]  s   r’   c                   C   s   dd„ t j ¡ D ƒS )Nc                 S   s4   i | ]\}}|  ¡ tv s| d ¡s|dkr||“qS )ÚUA_FEATURESÚUA_CONFIG_FILE)r[   r   Ú
startswith)rS   ÚkÚvr   r   r   Ú
<dictcomp>x  s    ÿüz'get_pro_environment.<locals>.<dictcomp>)ÚosÚenvironr.   r   r   r   r   Úget_pro_environmentw  s   þr›   c                 C   sž   dd„ }|  ¡ D ]D\}}|  |¡}t|tƒr#t|tƒr#t| | |ƒ qt|tƒrHt|tƒrHt|ƒrBt|d tƒrB|| | ||d� q	 || |< q|| |< qdS )aæ  Merge the contents of overlay dict into base_dict not only on top-level
    keys, but on all on the depths of the overlay_dict object. For example,
    using these values as entries for the function:

    base_dict = {"a": 1, "b": {"c": 2, "d": 3}}
    overlay_dict = {"b": {"c": 10}}

    Should update base_dict into:

    {"a": 1, "b": {"c": 10, "d": 3}}

    @param base_dict: The dict to be updated
    @param overlay_dict: The dict with information to be added into base_dict
    c           
      S   sx   ddddœ}g }|  |¡}|D ]%}d}t| ƒD ]\}}	|	  |¡|  |¡kr,t|	|ƒ d}q|s4| |¡ q|  |¡ d S )Nr   ÚtypeÚselector)ÚavailableResourcesÚresourceEntitlementsÚ	overridesFT)rH   Ú	enumerateÚdepth_first_merge_overlay_dictÚappendÚextend)
Úbase_valuesÚoverlay_valuesr2   Úmerge_id_key_mapÚvalues_to_appendÚid_keyÚoverlay_valueÚwas_replacedÚbase_value_idxÚ
base_valuer   r   r   Úupdate_dict_list‘  s"   ý

€
€z8depth_first_merge_overlay_dict.<locals>.update_dict_listr   )r2   N)r.   rH   r   rJ   r¢   Úlistr9   )Ú	base_dictÚoverlay_dictr®   r2   r3   r­   r   r   r   r¢   �  s   


ór¢   Úamd64Úi386Úppc64elÚarm64Úarmhf)Úx86_64Úi686Úppc64leÚaarch64Úarmv7lÚarchc                 C   s   |   ¡ }t ||¡S r   )r[   ÚARCH_ALIASESrH   )r¼   Ú
arch_lowerr   r   r   Ústandardize_arch_name¾  s   r¿   Úarchesc                 C   s*   t ƒ }| D ]	}| t|ƒ¡ qtt|ƒƒS r   )ÚsetÚaddr¿   Úsortedr¯   )rÀ   Údeduplicated_archesr¼   r   r   r   Údeduplicate_archesÃ  s   rÅ   c                   C   s   t  ¡ dkS )Nr   )r™   Úgetuidr   r   r   r   Úwe_are_currently_rootÊ  s   rÇ   ÚfilenameÚnew_extensionc                 C   s   t j | ¡\}}|d | S )Nr   )r™   rG   Úsplitext)rÈ   rÉ   r   Ú
_extensionr   r   r   Úset_filename_extensionÎ  s   rÌ   Úpackage_listc              
   C   s&   d  tjd  | ¡dddddd�¡d S )NÚ
rˆ   éP   Fz  )ÚwidthÚbreak_long_wordsÚbreak_on_hyphensÚinitial_indentÚsubsequent_indent)r   ÚtextwrapÚwrap)rÍ   r   r   r   Úcreate_package_list_strÓ  s   úÿ
öÿr×   )r   )r   FF)5r   ÚjsonÚloggingr™   rs   r‹   rÕ   r:   Ú	functoolsr   Útypingr   r   r   r   r   rV   r	   r
   Úuaclient.defaultsr   Úuaclient.typesr   ÚobjectrI   r/   r   Ú	getLoggerr#   r7   ÚJSONEncoderr   ÚJSONDecoderr(   rD   rK   r^   Úboolrd   rp   ÚREDACT_SENSITIVE_LOGSrx   r}   r0   r’   r›   r¢   r½   r¿   rÅ   rÇ   rÌ   r×   r   r   r   r   Ú<module>   s�    		"!ÿ
ÿ
ÿÿ

þ ÿÿÿÿ
þ' ÿÿ
þ
ÿÿ
þ7
5û	ÿ