a
    á `X>  ã                   @   s:  d 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 ddl
mZ ddl
mZ ddl
mZ ddl
mZ dd	lmZ dd
lmZ ddlmZ e e¡Zdd„ Zdd„ Zdd„ Zdd„ Zdd„ Zdd„ Zdd„ Zdd„ Z dd„ Z!dd„ Z"dd „ Z#d.d"d#„Z$d/d$d%„Z%d&d'„ Z&d(d)„ Z'd*d+„ Z(d,d-„ Z)dS )0z Tools for managing certificates.é    N)ÚList)Úcrypto_util)Úerrors)Ú
interfaces)Úocsp)Úutil)Ústorage)Úosc                 C   s$   t  | ¡D ]}t j|| dd q
dS )aj  Update the certificate file family symlinks to use archive_dir.

    Use the information in the config file to make symlinks point to
    the correct archive directory.

    .. note:: This assumes that the installation is using a Reverter object.

    :param config: Configuration.
    :type config: :class:`certbot._internal.configuration.NamespaceConfig`

    T)Zupdate_symlinksN)r   Úrenewal_conf_filesÚRenewableCert)ÚconfigÚrenewal_file© r   ú@/usr/lib/python3/dist-packages/certbot/_internal/cert_manager.pyÚupdate_live_symlinks   s    r   c                 C   sž   t j tj¡}t| dƒd }| j}|sX|jd |¡ddd\}}|t	j
ksN|sXt d¡‚t| |ƒ}|svt d |¡¡‚t ||| ¡ |jd	 ||¡d
d dS )z¡Rename the specified lineage to the new name.

    :param config: Configuration.
    :type config: :class:`certbot._internal.configuration.NamespaceConfig`

    Úrenamer   z&Enter the new name for certificate {0}z--updated-cert-nameT)ÚflagÚforce_interactiveúUser ended interaction.z,No existing certificate with name {0} found.z Successfully renamed {0} to {1}.F)ÚpauseN)ÚzopeÚ	componentÚ
getUtilityr   ÚIDisplayÚget_certnamesÚnew_certnameÚinputÚformatÚdisplay_utilÚOKr   ÚErrorÚlineage_for_certnameZConfigurationErrorr   Zrename_renewal_configÚnotification)r   ÚdispÚcertnamer   ÚcodeÚlineager   r   r   Úrename_lineage)   s*    þ


ÿÿÿr'   c                 C   sš   g }g }t  | ¡D ]v}z$t  || ¡}t |¡ | |¡ W q ty† } z4t d||¡ t 	dt
 ¡ ¡ | |¡ W Y d}~qd}~0 0 qt| ||ƒ dS )zªDisplay information about certs configured with Certbot

    :param config: Configuration.
    :type config: :class:`certbot._internal.configuration.NamespaceConfig`
    zIRenewal configuration file %s produced an unexpected error: %s. Skipping.úTraceback was:
%sN)r   r
   r   r   Zverify_renewable_certÚappendÚ	ExceptionÚloggerZwarningÚdebugÚ	tracebackÚ
format_excÚ_describe_certs)r   Úparsed_certsÚparse_failuresr   Zrenewal_candidateÚer   r   r   ÚcertificatesE   s    
ÿ"r3   c                 C   s   t | ddd}tj tj¡}dg}|D ]}| d| ¡ q&| d¡ |jd |¡ddsft	 
d	¡ d
S |D ] }t | |¡ t d |¡¡ qjd
S )z;Delete Certbot files associated with a certificate lineage.ÚdeleteT)Úallow_multiplez8The following certificate(s) are selected for deletion:
z  * z:
Are you sure you want to delete the above certificate(s)?Ú
)Údefaultz$Deletion of certificate(s) canceled.Nz.Deleted all files relating to certificate {0}.)r   r   r   r   r   r   r)   ZyesnoÚjoinr+   Úinfor   Zdelete_filesr   Únotifyr   )r   Ú	certnamesr#   Úmsgr$   r   r   r   r4   \   s    

ÿr4   c              	   C   s†   | j }tj|dd zt | |¡}W n tjy:   Y dS 0 zt || ¡W S  tjtfy€   t	 
d|¡ t	 
dt ¡ ¡ Y dS 0 dS )z)Find a lineage object with name certname.éí  ©ÚmodeNzRenewal conf file %s is broken.r(   )Úrenewal_configs_dirr   Úmake_or_verify_dirr   Zrenewal_file_for_certnamer   ÚCertStorageErrorr   ÚIOErrorr+   r,   r-   r.   )Ú
cli_configr$   Úconfigs_dirr   r   r   r   r!   p   s    r!   c                 C   s   t | |ƒ}|r| ¡ S dS )z0Find the domains in the cert with name certname.N)r!   Únames)r   r$   r&   r   r   r   Údomains_for_certname   s    
rG   c                    s   ‡ fdd„}t | |dƒS )aˆ  Find existing certs that match the given domain names.

    This function searches for certificates whose domains are equal to
    the `domains` parameter and certificates whose domains are a subset
    of the domains in the `domains` parameter. If multiple certificates
    are found whose names are a subset of `domains`, the one whose names
    are the largest subset of `domains` is returned.

    If multiple certificates' domains are an exact match or equally
    sized subsets, which matching certificates are returned is
    undefined.

    :param config: Configuration.
    :type config: :class:`certbot._internal.configuration.NamespaceConfig`
    :param domains: List of domain names
    :type domains: `list` of `str`

    :returns: lineages representing the identically matching cert and the
        largest subset if they exist
    :rtype: `tuple` of `storage.RenewableCert` or `None`

    c                    sb   |\}}t |  ¡ ƒ}|t ˆ ƒkr&| }n4| t ˆ ƒ¡rZ|du rB| }nt|ƒt| ¡ ƒkrZ| }||fS )zsReturn cert as identical_names_cert if it matches,
           or subset_names_cert if it matches as subset
        N)ÚsetrF   ÚissubsetÚlen)Úcandidate_lineageÚrvZidentical_names_certZsubset_names_certZcandidate_names©Údomainsr   r   Úupdate_certs_for_domain_matchesž   s    z?find_duplicative_certs.<locals>.update_certs_for_domain_matches)NN)Ú_search_lineages)r   rN   rO   r   rM   r   Úfind_duplicative_certs‡   s    rQ   c                    s,   | j ‰ ‡ ‡fdd„t ˆ ¡D ƒ}|r(|S dS )aJ   In order to match things like:
        /etc/letsencrypt/archive/example.com/chain1.pem.

        Anonymous functions which call this function are eventually passed (in a list) to
        `match_and_check_overlaps` to help specify the acceptable_matches.

        :param `.storage.RenewableCert` candidate_lineage: Lineage whose archive dir is to
            be searched.
        :param str filetype: main file name prefix e.g. "fullchain" or "chain".

        :returns: Files in candidate_lineage's archive dir that match the provided filetype.
        :rtype: list of str or None
    c                    s,   g | ]$}t  d  ˆ¡|¡rtj ˆ |¡‘qS )z{0}[0-9]*.pem)ÚreÚmatchr   r	   Úpathr8   )Ú.0Úf©Úarchive_dirÚfiletyper   r   Ú
<listcomp>Ã   s   ÿz"_archive_files.<locals>.<listcomp>N)rX   r	   Úlistdir)rK   rY   Úpatternr   rW   r   Ú_archive_files´   s
    r]   c                   C   s   dd„ dd„ dd„ dd„ gS )zª Generates the list that's passed to match_and_check_overlaps. Is its own function to
    make unit testing easier.

    :returns: list of functions
    :rtype: list
    c                 S   s   | j S ©N)Zfullchain_path©Úxr   r   r   Ú<lambda>Ñ   ó    z%_acceptable_matches.<locals>.<lambda>c                 S   s   | j S r^   ©Ú	cert_pathr_   r   r   r   ra   Ñ   rb   c                 S   s
   t | dƒS )NÚcert©r]   r_   r   r   r   ra   Ò   rb   c                 S   s
   t | dƒS )NÚ	fullchainrf   r_   r   r   r   ra   Ò   rb   r   r   r   r   r   Ú_acceptable_matchesÊ   s    ÿrh   c                    s(   t ƒ }tˆ |‡ fdd„dd„ ƒ}|d S )a“   If config.cert_path is defined, try to find an appropriate value for config.certname.

    :param `configuration.NamespaceConfig` cli_config: parsed command line arguments

    :returns: a lineage name
    :rtype: str

    :raises `errors.Error`: If the specified cert path can't be matched to a lineage name.
    :raises `errors.OverlappingMatchFound`: If the matched lineage's archive is shared.
    c                    s
   ˆ j d S )Nr   rc   r_   ©rD   r   r   ra   â   rb   z&cert_path_to_lineage.<locals>.<lambda>c                 S   s   | j S r^   )Úlineagenamer_   r   r   r   ra   â   rb   r   )rh   Úmatch_and_check_overlaps)rD   Úacceptable_matchesrS   r   ri   r   Úcert_path_to_lineageÕ   s
    ÿrm   c                    sP   ‡ ‡fdd„}t | |g |ƒ}|s8t d | jd ¡¡‚nt|ƒdkrLt ¡ ‚|S )a   Searches through all lineages for a match, and checks for duplicates.
    If a duplicate is found, an error is raised, as performing operations on lineages
    that have their properties incorrectly duplicated elsewhere is probably a bad idea.

    :param `configuration.NamespaceConfig` cli_config: parsed command line arguments
    :param list acceptable_matches: a list of functions that specify acceptable matches
    :param function match_func: specifies what to match
    :param function rv_func: specifies what to return

    c                    s`   ‡ fdd„|D ƒ}g }|D ]"}t |tƒr2||7 }q| |¡ qˆˆ ƒ}||v r\| ˆˆ ƒ¡ |S )z1Returns a list of matches using _search_lineages.c                    s   g | ]}|ˆ ƒ‘qS r   r   )rU   Úfunc©rK   r   r   rZ   ó   rb   zBmatch_and_check_overlaps.<locals>.find_matches.<locals>.<listcomp>)Ú
isinstanceÚlistr)   )rK   Zreturn_valuerl   Zacceptable_matches_rvÚitemrS   ©Ú
match_funcÚrv_funcro   r   Úfind_matchesñ   s    

z.match_and_check_overlaps.<locals>.find_matchesz!No match found for cert-path {0}!r   é   )rP   r   r    r   rd   rJ   ZOverlappingMatchFound)rD   rl   rt   ru   rv   Zmatchedr   rs   r   rk   æ   s    rk   Fc                 C   sB  g }t  ¡ }| jr&|j| jkr&|s&dS | jrDt| jƒ | ¡ ¡sDdS tj	 
tj ¡ ¡}g }|jrj| d¡ |j|kr€| d¡ n| |¡r”| d¡ |r¨dd |¡ }nB|j| }|jdkrÂd}n(|jdk rÞd	 |jd
 ¡}nd |j¡}d |j|¡}	tt |j¡dƒ}
| d |j|
|jd | ¡ ¡|	|j|j¡¡ d |¡S )zJ Returns a human readable description of info about a RenewableCert objectÚ Z	TEST_CERTZEXPIREDZREVOKEDz	INVALID: z, rw   zVALID: 1 dayzVALID: {0} hour(s)i  zVALID: {0} daysz	{0} ({1})r`   z“  Certificate Name: {}
    Serial Number: {}
    Key Type: {}
    Domains: {}
    Expiry Date: {}
    Certificate Path: {}
    Private Key Path: {}ú )r   ZRevocationCheckerr$   rj   rN   rH   rI   rF   ÚpytzZUTCZfromutcÚdatetimeZutcnowZis_test_certr)   Ztarget_expiryZocsp_revokedr8   Zdaysr   Zsecondsr   Zget_serial_from_certrd   Zprivate_key_typerg   Zprivkey)r   re   Zskip_filter_checksÚcertinfoZcheckerZnowZreasonsZstatusZdiffZvalid_stringÚserialr   r   r   Úhuman_readable_cert_info  sD    






ór~   c                 C   sè   | j }|r|g}nÒtj tj¡}t | ¡}dd„ |D ƒ}|sFt 	d¡‚|rŠ|sZd 
|¡}	n|}	|j|	|ddd\}
}|
tjkrät 	d¡‚nZ|sšd	 
|¡}	n|}	|j|	|ddd\}
}|
tjksÐ|td
t|ƒƒvrÚt 	d¡‚|| g}|S )z9Get certname from flag, interactively, or error out.
    c                 S   s   g | ]}t  |¡‘qS r   )r   Zlineagename_for_filename)rU   Únamer   r   r   rZ   A  rb   z!get_certnames.<locals>.<listcomp>zNo existing certificates found.z+Which certificate(s) would you like to {0}?z--cert-nameT)Zcli_flagr   r   z(Which certificate would you like to {0}?r   )r$   r   r   r   r   r   r   r
   r   r    r   Z	checklistr   r   ZmenuÚrangerJ   )r   Zverbr5   Zcustom_promptr$   r;   r#   Ú	filenamesÚchoicesÚpromptr%   Úindexr   r   r   r   8  s6    

ÿ

ÿ


r   c                 C   s   dd  dd„ | D ƒ¡ S )zFFormat a results report for a category of single-line renewal outcomesz  z
  c                 s   s   | ]}t |ƒV  qd S r^   )Ústr)rU   r<   r   r   r   Ú	<genexpr>b  rb   z _report_lines.<locals>.<genexpr>)r8   )Zmsgsr   r   r   Ú_report_lines`  s    r‡   c                 C   s(   g }|D ]}|  t| |ƒ¡ qd |¡S )z)Format a results report for a parsed certr6   )r)   r~   r8   )r   r0   r|   re   r   r   r   Ú_report_human_readablee  s    rˆ   c                 C   s   g }|j }|s|s|dƒ nL|rP| js,| jr0dnd}|d |¡ƒ |t| |ƒƒ |rh|dƒ |t|ƒƒ tj t	j
¡}|jd |¡ddd d	S )
z/Print information about the certs we know aboutzNo certificates found.z	matching rx   zFound the following {0}certs:z3
The following renewal configurations were invalid:r6   F)r   ZwrapN)r)   r$   rN   r   rˆ   r‡   r   r   r   r   r   r"   r8   )r   r0   r1   Úoutr:   rS   r#   r   r   r   r/   m  s    
r/   c              
   G   sˆ   | j }tj|dd |}t | ¡D ]`}zt || ¡}W n8 tjtfyn   t	 
d|¡ t	 
dt ¡ ¡ Y q"Y n0 |||g|¢R Ž }q"|S )aâ  Iterate func over unbroken lineages, allowing custom return conditions.

    Allows flexible customization of return values, including multiple
    return values and complex checks.

    :param `configuration.NamespaceConfig` cli_config: parsed command line arguments
    :param function func: function used while searching over lineages
    :param initial_rv: initial return value of the function (any type)

    :returns: Whatever was specified by `func` if a match is found.
    r=   r>   z)Renewal conf file %s is broken. Skipping.r(   )r@   r   rA   r   r
   r   r   rB   rC   r+   r,   r-   r.   )rD   rn   Z
initial_rvÚargsrE   rL   r   rK   r   r   r   rP   ƒ  s    
rP   )F)FN)*Ú__doc__r{   ZloggingrR   r-   rz   Zzope.componentr   Zacme.magic_typingr   Zcertbotr   r   r   r   r   Zcertbot._internalr   Zcertbot.compatr	   Zcertbot.displayr   Z	getLoggerÚ__name__r+   r   r'   r3   r4   r!   rG   rQ   r]   rh   rm   rk   r~   r   r‡   rˆ   r/   rP   r   r   r   r   Ú<module>   sB   
-!
1
(