a
    `.                     @   s   d Z ddlZddlZddlm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 eeZejejejejG dd dejZG dd de Z!dd Z"dd Z#dd Z$dS )z*Common code for DNS Authenticator Plugins.    N)sleep)
challenges)errors)
interfaces)
filesystem)os)ops)util)commonc                       s   e Zd ZdZ fddZed ddZdd Zd	d
 Zdd Z	dd Z
ejdd Zejdd Zejdd Zdd Zd!ddZd"ddZedd Zed#ddZ  ZS )$DNSAuthenticatorz"Base class for DNS  Authenticatorsc                    s   t t| || d| _d S )NF)superr   __init___attempt_cleanup)selfconfigname	__class__ </usr/lib/python3/dist-packages/certbot/plugins/dns_common.pyr      s    zDNSAuthenticator.__init__
   c                 C   s   |d|t dd d S )Npropagation-secondszjThe number of seconds to wait for DNS to propagate before asking the ACME server to verify the DNS record.)defaulttypehelp)int)clsaddZdefault_propagation_secondsr   r   r   add_parser_arguments    s
    z%DNSAuthenticator.add_parser_argumentsc                 C   s   t jgS N)r   ZDNS01)r   Zunused_domainr   r   r   get_chall_pref(   s    zDNSAuthenticator.get_chall_prefc                 C   s   d S r   r   r   r   r   r   prepare+   s    zDNSAuthenticator.preparec                 C   s|   |    d| _g }|D ]@}|j}||}||j}| ||| |||j qt	
d| d t| d |S )NTz/Waiting %d seconds for DNS changes to propagater   )_setup_credentialsr   domainvalidation_domain_name
validationaccount_key_performappendresponseloggerinfoconfr   )r   achallsZ	responsesachallr$   r%   r&   r   r   r   perform.   s    
zDNSAuthenticator.performc                 C   s>   | j r:|D ].}|j}||}||j}| ||| q
d S r   )r   r$   r%   r&   r'   _cleanup)r   r.   r/   r$   r%   r&   r   r   r   cleanupE   s    
zDNSAuthenticator.cleanupc                 C   s
   t  dS )z@
        Establish credentials, prompting if necessary.
        NNotImplementedErrorr!   r   r   r   r#   N   s    z#DNSAuthenticator._setup_credentialsc                 C   s
   t  dS )aX  
        Performs a dns-01 challenge by creating a DNS TXT record.

        :param str domain: The domain being validated.
        :param str validation_domain_name: The validation record domain name.
        :param str validation: The validation record content.
        :raises errors.PluginError: If the challenge cannot be performed
        Nr3   r   r$   Zvalidation_namer&   r   r   r   r(   U   s    
zDNSAuthenticator._performc                 C   s
   t  dS )aX  
        Deletes the DNS TXT record which would have been created by `_perform_achall`.

        Fails gracefully if no such record exists.

        :param str domain: The domain being validated.
        :param str validation_domain_name: The validation record domain name.
        :param str validation: The validation record content.
        Nr3   r5   r   r   r   r1   a   s    zDNSAuthenticator._cleanupc                 C   s0   |  |}|s,| |}t| j| || dS )a  
        Ensure that a configuration value is available.

        If necessary, prompts the user and stores the result.

        :param str key: The configuration key.
        :param str label: The user-friendly label for this piece of information.
        N)r-   _prompt_for_datasetattrr   dest)r   keylabelconfigured_value	new_valuer   r   r   
_configuren   s    


zDNSAuthenticator._configureNc                 C   sB   |  |}|s>| ||}t| j| |tjtj| dS )a  
        Ensure that a configuration value is available for a path.

        If necessary, prompts the user and stores the result.

        :param str key: The configuration key.
        :param str label: The user-friendly label for this piece of information.
        N)	r-   _prompt_for_filer7   r   r8   r   pathabspath
expanduser)r   r9   r:   	validatorr;   r<   r   r   r   _configure_file~   s    

z DNSAuthenticator._configure_filec                    sN    fdd} ||| t|j} r>|  rJ| |S )a  
        As `_configure_file`, but for a credential configuration file.

        If necessary, prompts the user and stores the result.

        Always stores absolute paths to avoid issues during renewal.

        :param str key: The configuration key.
        :param str label: The user-friendly label for this piece of information.
        :param dict required_variables: Map of variable which must be present to error to display.
        :param callable validator: A method which will be called to validate the
            `CredentialsConfiguration` resulting from the supplied input after it has been validated
            to contain the `required_variables`. Should throw a `~certbot.errors.PluginError` to
            indicate any issue.
        c                    s*   t | j} r|  r&| d S r   )CredentialsConfigurationr8   require)filenameZconfigurationrequired_variablesr   rB   r   r   __validator   s
    
z<DNSAuthenticator._configure_credentials.<locals>.__validator)rC   rD   r-   r8   rE   )r   r9   r:   rH   rB   _DNSAuthenticator__validatorZcredentials_configurationr   rG   r   _configure_credentials   s    	
z'DNSAuthenticator._configure_credentialsc                    sH    fdd}t j|d dd\}}|tjkr4|S td dS )z
        Prompt the user for a piece of information.

        :param str label: The user-friendly label for this piece of information.
        :returns: The user's response (guaranteed non-empty).
        :rtype: str
        c                    s   | st d d S )NzPlease enter your {0}.)r   PluginErrorformat)ir:   r   r   rI      s    z6DNSAuthenticator._prompt_for_data.<locals>.__validatorzInput your {0}TZforce_interactive{0} required to proceed.N)r   Zvalidated_inputrM   display_utilOKr   rL   )r:   rJ   coder*   r   rO   r   r6      s    


z!DNSAuthenticator._prompt_for_datac                    sJ    fdd}t j|d dd\}}|tjkr6|S td dS )a  
        Prompt the user for a path.

        :param str label: The user-friendly label for the file.
        :param callable validator: A method which will be called to validate the supplied input
            after it has been validated to be a non-empty path to an existing file. Should throw a
            `~certbot.errors.PluginError` to indicate any issue.
        :returns: The user's response (guaranteed to exist).
        :rtype: str
        c                    s8   | st d tj| } t|  r4|  d S )Nz&Please enter a valid path to your {0}.)r   rL   rM   r   r?   rA   validate_filerF   r:   rB   r   r   rI      s    z6DNSAuthenticator._prompt_for_file.<locals>.__validatorzInput the path to your {0}TrP   rQ   N)r   Zvalidated_directoryrM   rR   rS   r   rL   )r:   rB   rJ   rT   r*   r   rW   r   r>      s    

z!DNSAuthenticator._prompt_for_file)r   )N)NN)N)__name__
__module____qualname____doc__r   classmethodr   r    r"   r0   r2   abcabstractmethodr#   r(   r1   r=   rC   rK   staticmethodr6   r>   __classcell__r   r   r   r   r      s*   	




%
r   c                   @   s@   e Zd ZdZdd fddZdd Zdd	 Zd
d Zdd ZdS )rD   z>Represents a user-supplied filed which stores API credentials.c                 C   s   | S r   r   )xr   r   r   <lambda>       z!CredentialsConfiguration.<lambda>c              
   C   sj   t | zt|| _W nF tjy^ } z,tjd|dd td	|W Y d}~n
d}~0 0 || _
dS )z
        :param str filename: A path to the configuration file.
        :param callable mapper: A transformation to apply to configuration key names
        :raises errors.PluginError: If the file does not exist or is not a valid format.
        z+Error parsing credentials configuration: %sT)exc_infoz,Error parsing credentials configuration: {0}N)validate_file_permissions	configobjZ	ConfigObjconfobjZConfigObjErrorr+   debugr   rL   rM   mapper)r   rF   ri   er   r   r   r      s    &z!CredentialsConfiguration.__init__c              	   C   s   g }|D ]R}|  |s4|d| |||  q| |s|d| |||  q|rtdt|dkrxdnd| jj	d
|dS )	zEnsures that the supplied set of variables are all present in the file.

        :param dict required_variables: Map of variable which must be present to error to display.
        :raises errors.PluginError: If one or more are missing.
        z)Property "{0}" not found (should be {1}).z'Property "{0}" not set (should be {1}).z9Missing {0} in credentials configuration file {1}:
 * {2}   propertyZ
propertiesz
 * N)_hasr)   rM   ri   _getr   rL   lenrg   rF   join)r   rH   Zmessagesvarr   r   r   rE      s$    

z CredentialsConfiguration.requirec                 C   s
   |  |S )zFind a configuration value for variable `var`, as transformed by `mapper`.

        :param str var: The variable to get.
        :returns: The value of the variable.
        :rtype: str
        )rn   r   rq   r   r   r   r-     s    zCredentialsConfiguration.confc                 C   s   |  || jv S r   )ri   rg   rr   r   r   r   rm   "  s    zCredentialsConfiguration._hasc                 C   s   | j | |S r   )rg   getri   rr   r   r   r   rn   %  s    zCredentialsConfiguration._getN)	rX   rY   rZ   r[   r   rE   r-   rm   rn   r   r   r   r   rD      s   
rD   c                 C   s<   t j| std| t j| r8td| dS )z&Ensure that the specified file exists.zFile not found: {0}zPath is a directory: {0}N)r   r?   existsr   rL   rM   isdirrV   r   r   r   rU   )  s    rU   c                 C   s"   t |  t| rtd|  dS )zHEnsure that the specified file exists and warn about unsafe permissions.z8Unsafe permissions on credentials configuration file: %sN)rU   r   Zhas_world_permissionsr+   ZwarningrV   r   r   r   re   3  s    
re   c                    s&   |  d  fddtdt D S )a  Return a list of progressively less-specific domain names.

    One of these will probably be the domain name known to the DNS provider.

    :Example:

    >>> base_domain_name_guesses('foo.bar.baz.example.com')
    ['foo.bar.baz.example.com', 'bar.baz.example.com', 'baz.example.com', 'example.com', 'com']

    :param str domain: The domain for which to return guesses.
    :returns: The a list of less specific domain names.
    :rtype: list
    .c                    s   g | ]}d   |d qS )rv   N)rp   ).0rN   Z	fragmentsr   r   
<listcomp>L  rc   z,base_domain_name_guesses.<locals>.<listcomp>r   )splitrangero   )r$   r   rx   r   base_domain_name_guesses<  s    
r|   )%r[   r]   Zloggingtimer   rf   Zzope.interfacezopeZacmer   Zcertbotr   r   Zcertbot.compatr   r   Zcertbot.displayr   r	   rR   Zcertbot.pluginsr
   Z	getLoggerrX   r+   Z	interfaceZimplementerZIAuthenticatorZproviderZIPluginFactoryZPluginr   objectrD   rU   re   r|   r   r   r   r   <module>   s,   
 U=
	