U
    ÝÁ]
<  ã                   @   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)Ústorage)Úutil)Úosc                 C   s$   t  | ¡D ]}t j|| dd q
dS )a`  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.configuration.NamespaceConfig`

    T)Zupdate_symlinksN)r   Úrenewal_conf_filesÚRenewableCert)ÚconfigÚrenewal_file© r   ú6/usr/lib/python3/dist-packages/certbot/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.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 ]t}z$t  || ¡}t |¡ | |¡ W q tk
r„ } z,t d||¡ t 	dt
 ¡ ¡ | |¡ W 5 d}~X Y qX qt| ||ƒ dS )z Display information about certs configured with Certbot

    :param config: Configuration.
    :type config: :class:`certbot.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    
 ÿr4   c                 C   sJ   t | ddd}|D ]2}t | |¡ tj tj¡}|jd 	|¡dd qdS )z;Delete Certbot files associated with a certificate lineage.ÚdeleteT)Úallow_multiplez.Deleted all files relating to certificate {0}.Fr   N)
r   r   Zdelete_filesr   r   r   r   r   r#   r   )r   Ú	certnamesr%   r$   r   r   r   r5   [   s    ÿÿr5   c              	   C   sŠ   | j }tj|dd zt | |¡}W n tjk
r<   Y dS X zt || ¡W S  tjtfk
r„   t	 
d|¡ t	 
dt ¡ ¡ Y dS X 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"   h   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_certnamex   s    
rB   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.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k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)ÚsetrA   Ú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   rI   rJ   r   rH   r   Úfind_duplicative_certs}   s    rL   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	   ÚpathÚjoin)Ú.0Úf©Úarchive_dirÚfiletyper   r   Ú
<listcomp>¸   s    ÿz"_archive_files.<locals>.<listcomp>N)rT   r	   Úlistdir)rF   rU   Úpatternr   rS   r   Ú_archive_files©   s
    rY   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 rZ   ©Ú	cert_pathr[   r   r   r   r]   Å   r^   c                 S   s
   t | dƒS )NÚcert©rY   r[   r   r   r   r]   Æ   r^   c                 S   s
   t | dƒS )NÚ	fullchainrb   r[   r   r   r   r]   Æ   r^   r   r   r   r   r   Ú_acceptable_matches¾   s     ÿrd   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   r_   r[   ©r?   r   r   r]   Õ   r^   z&cert_path_to_lineage.<locals>.<lambda>c                 S   s   | j S rZ   )Úlineagenamer[   r   r   r   r]   Õ   r^   r   )rd   Úmatch_and_check_overlaps)r?   Úacceptable_matchesrN   r   re   r   Úcert_path_to_lineageÈ   s    
 ÿri   c                    sV   ‡ ‡fdd„}t | |g |ƒ}|s8t d | jd ¡¡‚nt|ƒdkrNt ¡ ‚n|S d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ˆˆ ƒ}||kr\| ˆˆ ƒ¡ |S )z1Returns a list of matches using _search_lineages.c                    s   g | ]}|ˆ ƒ‘qS r   r   )rQ   Úfunc©rF   r   r   rV   å   s     zBmatch_and_check_overlaps.<locals>.find_matches.<locals>.<listcomp>)Ú
isinstanceÚlistr*   )rF   Zreturn_valuerh   Zacceptable_matches_rvÚitemrN   ©Ú
match_funcÚrv_funcrk   r   Úfind_matchesã   s    

z.match_and_check_overlaps.<locals>.find_matchesz!No match found for cert-path {0}!r   é   N)rK   r   r!   r   r`   rE   ZOverlappingMatchFound)r?   rh   rp   rq   rr   Zmatchedr   ro   r   rg   Ø   s    
rg   Fc           
   	   C   s*  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|¡}	| d |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, rs   zVALID: 1 dayzVALID: {0} hour(s)i  zVALID: {0} daysz	{0} ({1})zq  Certificate Name: {0}
    Domains: {1}
    Expiry Date: {2}
    Certificate Path: {3}
    Private Key Path: {4}ú )r   ZRevocationCheckerr%   rf   rI   rC   rD   rA   ÚpytzZUTCZfromutcÚdatetimeZutcnowZis_test_certr*   Ztarget_expiryZocsp_revokedrP   Zdaysr   Zsecondsrc   Zprivkey)
r   ra   Zskip_filter_checksÚcertinfoZcheckerZnowZreasonsZstatusZdiffZvalid_stringr   r   r   Úhuman_readable_cert_infoù   s>    






÷
ry   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|ƒƒk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)rQ   Únamer   r   r   rV   -  s     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ÚrangerE   )r   Zverbr6   Zcustom_promptr%   r7   r$   Ú	filenamesÚchoicesÚpromptr&   Úindexr   r   r   r   $  sB    

   ÿ

   ÿ


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 rZ   )Ústr)rQ   Úmsgr   r   r   Ú	<genexpr>M  s     z _report_lines.<locals>.<genexpr>)rP   )Zmsgsr   r   r   Ú_report_linesK  s    rƒ   c                 C   s(   g }|D ]}|  t| |ƒ¡ qd |¡S )z)Format a results report for a parsed certÚ
)r*   ry   rP   )r   r1   rx   ra   r   r   r   Ú_report_human_readableO  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 certs found.z	matching rt   zFound the following {0}certs:z3
The following renewal configurations were invalid:r„   F)r   ZwrapN)r*   r%   rI   r   r…   rƒ   r   r   r   r   r   r#   rP   )r   r1   r2   ÚoutZnotifyrN   r$   r   r   r   r0   V  s    
r0   c              
   G   sˆ   | j }tj|dd |}t | ¡D ]`}zt || ¡}W n: tjtfk
rp   t	 
d|¡ t	 
dt ¡ ¡ Y q"Y nX |||f|žŽ }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.
    r8   r9   z)Renewal conf file %s is broken. Skipping.r)   )r;   r   r<   r   r
   r   r   r=   r>   r,   r-   r.   r/   )r?   rj   Z
initial_rvÚargsr@   rG   r   rF   r   r   r   rK   k  s    
rK   )F)FN))Ú__doc__rw   ZloggingrM   r.   rv   Zzope.componentr   Zacme.magic_typingr   Zcertbotr   r   r   r   r   r   Zcertbot.compatr	   Zcertbot.displayr   Z	getLoggerÚ__name__r,   r   r(   r4   r5   r"   rB   rL   rY   rd   ri   rg   ry   r   rƒ   r…   r0   rK   r   r   r   r   Ú<module>   sB   
,
!
+
'