
    M/eď                     x   d 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 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rddlmZ 	 ddlmZ  ej:                  e      Z G d d      Z de!de!fdZ"de!de!fdZ#defdZ$y# e$ r dZY <w xY w)z@ApacheParser is a member object of the ApacheConfigurator class.    N)
Collection)Dict)Iterable)List)Mapping)Optional)Pattern)Set)Tuple)TYPE_CHECKING)Union)errors)os)apache_util)	constants)ApacheConfigurator)Augeasc                      e Zd ZU dZ ej
                  d      Zeed<   h dZ	e
e   ed<   	 dNdeddd	ed
eedf   ddf
dZdeddfdZdeeee   f   fdZde
e   fdZdOdZdee   ddfdZdee   ddfdZdededdfdZdeddfdZdOdZdOdZdOdZdOd ZdOd!ZdOd"Z d#ed$edee   fd%Z!d&ed'ed$ee   ddfd(Z"d&ed)edefd*Z#d&ed)edefd+Z$d&e%e   d'e%e   d$eee   ef   ddfd,Z&d&e%e   d-ed$eee   ef   ddfd.Z'd&ed/eddfd0Z(dPd1ed2e%e   dee   fd3Z)	 	 dQd'ed1e%e   d2e%e   d4edee   f
d5Z*d6ede%e   fd7Z+defd8Z,d#ee   dee   fd9Z-d6ed:eee.e   f   defd;Z/d1edefd<Z0d1e%e   de%e   fd=Z1d>edefd?Z2d@eddfdAZ3dBe%e   defdCZ4dBe%e   defdDZ5dBedEe6eee   f   defdFZ7d@edeeef   fdGZ8d@eddfdHZ9dIeddfdJZ:dOdKZ;de<eef   fdLZ=defdMZ>y)RApacheParsera  Class handles the fine details of parsing the Apache Configuration.

    .. todo:: Make parsing general... remove sites-available etc...

    :ivar str root: Normalized absolute path to the server root
        directory. Without trailing slash.
    :ivar set modules: All module names that are currently enabled.
    :ivar dict loc: Location to place directives, root - configuration origin,
        default - user config file, name - NameVirtualHost,

    z\$\{[^ \}]*}arg_var_interpreter>   *?[\]fnmatch_charsrootconfiguratorr   	vhostrootversion.returnNc                    || _         t               | _        | j                         st	        j
                  d      i | _        i | _        i | _        t        j                  j                  |      | _        d| j                         i| _        | j                  | j                  d          | j!                          | j#                          | j%                          | j                  j'                  | j)                                t+        j,                  | j                        | _        |rS| j                  t        j                  j                  |      dz   | j                   j0                  j2                  z          y y )NzApache plugin support requires libaugeas0 and augeas-lenses version 1.2.0 or higher, please make sure you have you have those installed.r   /)r   init_augeasaugcheck_aug_versionr   NotSupportedErrormodulesparser_paths	variablesr   pathabspathr   _find_config_rootloc
parse_fileupdate_runtime_variablesstandardize_exclparse_modulesupdate_set_locationscopydeepcopyexisting_pathsoptionsvhost_files)selfr   r   r   r    s        A/usr/lib/python3/dist-packages/certbot_apache/_internal/parser.py__init__zApacheParser.__init__2   s7    ) '=%%'**#$ $
 2424)+ .	$*D,B,B,D#E() 	%%' 	 	 	++-. #mmD,=,=> OOBGGOOI6< --55AAB C     lensc           	      p   | j                   j                  d      }|D ]  }| j                   j                  |dz         }|s$||v s)dj                  |dt	        |      dz
   | j                   j                  |dz         | j                   j                  |dz               }t        j                  |       y)	zVerify Augeas can parse all of the lens files.

        :param str lens: lens to check for errors

        :raises .errors.PluginError: If there has been an error in parsing with
            the specified lens.

        /augeas//errorz/lensz@There has been an error in parsing the file {0} on line {1}: {2}      z/line/messageN)r%   matchgetformatlenr   PluginError)r:   r>   error_filesr+   	lens_pathmsgs         r;   check_parsing_errorsz!ApacheParser.check_parsing_errorsa   s     hhnn%56 	.D TG^4ITY. &CIM*HHLL0HHLL
!23	5  ((--	.r=   c                     | j                   j                  dd       	 | j                   j                  d      }| j                   j	                  d       |S # t        $ r | j                   j	                  d       Y yw xY w)z Checks that we have recent enough version of libaugeas.
        If augeas version is recent enough, it will support case insensitive
        regexp matchingz/test/path/testing/argaRgUMeNTz,/test//*[self::arg=~regexp('argument', 'i')]z
/test/pathF)r%   setrD   RuntimeErrorremove)r:   matchess     r;   r&   zApacheParser.check_aug_version{   sm    
 	-z:	hhnn>@G
 	%	  	HHOOL)	s   A $A=<A=c                 b   | j                   j                  d      }| j                   j                  dd       | j                   j                  d      }	 | j                   j	                          | j                   j                  d|       | j                   j                  d      }t               }|r4|D ]/  }|j                  | j                   j                  |      dd        1 |S # t
        t        f$ r8 | j                  |       d| j                  _	        t        j                  d      w xY w)	a  Lists files that have modified Augeas DOM but the changes have not
        been written to the filesystem yet, used by `self.save()` and
        ApacheConfigurator to check the file state.

        :raises .errors.PluginError: If there was an error in Augeas, in
            an attempt to save the configuration, or an error creating a
            checkpoint

        :returns: `set` of unsaved files
        z/augeas/savenoopr@    z-Error saving files, check logs for more info.z/augeas/events/savedrB   N)r%   rE   rO   rD   saverP   IOError_log_save_errorsr   
save_notesr   rH   add)r:   
save_stateex_errs
save_paths
save_filesr+   s         r;   unsaved_fileszApacheParser.unsaved_files   s    XX\\.1
^V,((..!12	AHHMMO 	^Z0
 XX^^$:;
U
" 7txx||D1!"567' g& 	A!!'*+-D($$?A A		As   C' 'AD.c                     | j                         r:| j                  xj                  dz  c_        | j                  j                          yy)zMakes sure that all Augeas dom changes are written to files to avoid
        loss of configuration directives when doing additional augeas parsing,
        causing a possible augeas.load() resulting dom reset
        z
(autosave)N)r_   r   rY   rV   r:   s    r;   ensure_augeas_statez ApacheParser.ensure_augeas_state   s>     ((L8(""$  r=   r^   c                 T   d| j                   _        | j                  j                  d      }	 | j                  j	                          |r@|D ]   }| j                  j                  d|z          " | j                  j                          yy# t
        $ r | j                  |        w xY w)zSaves all changes to the configuration files.

        save() is called from ApacheConfigurator to handle the parser specific
        tasks of saving.

        :param list save_files: list of strings of file paths that we need to save.

        rU   r@   z/files/N)	r   rY   r%   rD   rV   rW   rX   rQ   load)r:   r^   r\   sfs       r;   rV   zApacheParser.save   s     (*$((..!12	HHMMO   .	"-.HHMMO   	!!'*	s   B B'r\   c           
         | j                   j                  d      D cg c]	  }||vs| }}|D ]^  }t        j                  d| j                   j	                  |      |dt        |      dz
   | j                   j	                  | d             ` t        j                  ddj                  d |D              | j                  j                  rd	| j                  j                          yd
       yc c}w )zfLog errors due to bad Augeas save.

        :param list ex_errs: Existing errors before save

        r@   zError %s saving %s: %srA   rB   rC   zUnable to save files: %s.%sz, c              3   >   K   | ]  }|d t        |      dz
     yw)rA   rB   N)rG   ).0errs     r;   	<genexpr>z0ApacheParser._log_save_errors.<locals>.<genexpr>   s     4^cSCHqL5I4^s   z Save Notes: rU   N)
r%   rD   loggerdebugrE   rG   errorjoinr   rY   )r:   r\   enew_errsri   s        r;   rX   zApacheParser._log_save_errors   s      $xx~~.>?T!1GCSATT 	0CLL($((,,s*;SCHqL=QuH-.0	0 	)4994^U]4^+^>B>O>O>Z>ZmD--889:	d`b	d Us
   	C3C3main_configinc_pathc                    | j                  t        d      |      st        j                  d|t	        |             | j                  t	        |      d|       t        j                  j                  |      }t        j                  j                  |      }| j                  j                  |g       j                  |       yy)zAdd Include for a new configuration file if one does not exist

        :param str main_config: file path to main Apache config file
        :param str inc_path: path of file to include

        IncludezAdding Include %s to %sN)find_dircase_irk   rl   get_aug_pathadd_dirr   r+   dirnamebasenamer7   
setdefaultappend)r:   rq   rr   new_dirnew_files        r;   add_includezApacheParser.add_include   s     }}VI.9LL2!<#<>LL[)8%
 ggooh/Gww''1H**7B7>>xH :r=   mod_namec                     |dz   | j                   vrd| j                   |dz   <   d|z   dz   | j                   vrd| j                   d|z   dz   <   yy)z%Shortcut for updating parser modules._moduleNmod_z.c)r(   )r:   r   s     r;   add_modzApacheParser.add_mod   sY    it||315DLLI-.Ht#4<<759DLL(*T12 8r=   c                 R    i | _         | j                          | j                          y)zgReset the loaded modules list. This is called from cleanup to clear
        temporarily loaded modules.N)r(   update_modulesr2   ra   s    r;   reset_moduleszApacheParser.reset_modules   s#     r=   c                    i }| j                  d      }t        |      }d}t        |      |k7  rt        |      }t        ||      D ]r  \  }}| j	                  |      }| j	                  |      }|r0|r.|||<   ||t
        j                  j                  |      dd dz   <   Zt        j                  d|dd        t t        |      |k7  r| j                  j                  |       y)zIterates on the configuration until no new modules are loaded.

        ..todo:: This should be attempted to be done with a binary to avoid
            the iteration issue.  Else... parse and enable mods at same time.

        
LoadModuleNcz8Could not read LoadModule directive from Augeas path: %srB   )ru   iterrG   zipget_argr   r+   rz   rk   rl   r(   r3   )	r:   modsrR   iterator	prev_size
match_namematch_filenamer   mod_filenames	            r;   r2   zApacheParser.parse_modules  s      "---=	$i9$D	I.1h/( 	1*
N<<
3#||N;%1DNFRD)),7<sBCLL![!+AB1	1 $i9$ 	D!r=   c                 d    | j                          | j                          | j                          y)zAUpdate Includes, Defines and Includes from httpd config dump dataN)update_definesupdate_includesr   ra   s    r;   r0   z%ApacheParser.update_runtime_variables"  s(     	r=   c                 t    t        j                  | j                  j                  j                        | _        y)z>Updates the dictionary of known variables in the configurationN)r   parse_definesr   r8   get_defines_cmdr*   ra   s    r;   r   zApacheParser.update_defines)  s&    $2243D3D3L3L3\3\]r=   c                     | j                  d      }t        j                  | j                  j                  j
                        }|r+|D ]%  }| j                  |      r| j                  |       ' yy)z>Get includes from httpd process, and add them to DOM if neededrt   N)ru   r   parse_includesr   r8   get_includes_cmdparsed_in_currentr/   )r:   _rR   is       r;   r   zApacheParser.update_includes-  se     MM)$,,T->->-F-F-W-WX '--a0OOA&' r=   c                     t        j                  | j                  j                  j                        }|D ]!  }| j                  |j                                # y)z:Get loaded modules from httpd process, and add them to DOMN)r   r2   r   r8   get_modules_cmdr   strip)r:   rR   mods      r;   r   zApacheParser.update_modules;  sG     ++D,=,=,E,E,U,UV 	&CLL%	&r=   rR   argsc           	         g }|dk(  r>t        |      D ].  \  }}|j                  d      s|j                  ||   dd        0 |S t        |      D ]m  \  }}|j                  d|z        s|t        |      dz
  k(  s||dz      j                  d|dz   z        rJ|j                  ||   dt        d|z                 o |S )a  Filter out directives with specific number of arguments.

        This function makes the assumption that all related arguments are given
        in order.  Thus /files/apache/directive[5]/arg[2] must come immediately
        after /files/apache/directive[5]/arg[1]. Runs in 1 linear pass.

        :param str matches: Matches of all directives with arg nodes
        :param int args: Number of args you would like to filter

        :returns: List of directives that contain # of arguments.
            (arg is stripped off)

           /argN/arg[%d])	enumerateendswithr|   rG   )r:   rR   r   filteredr   rD   s         r;   filter_args_numzApacheParser.filter_args_numB  s     !19%g. 55>>&)OOGAJsO45  &g. N5>>*t"34 c'lQ./ 'A 7 7
9=9C !D 
3KSd9J5K4K(LMN r=   aug_conf_path	directivec                 z   | j                  |d      }| j                  j                  |dz   dd       |dz   }| j                  j                  ||       t	        |      dk(  r#| j                  j                  |dz   |d          y
t        |      D ])  \  }}| j                  j                  d	||dz   fz  |       + y
)a  Adds directive and value to IfMod ssl block.

        Adds given directive and value along configuration path within
        an IfMod mod_ssl.c block.  If the IfMod block does not exist in
        the file, it is created.

        :param str aug_conf_path: Desired Augeas config path to add directive
        :param str directive: Directive you would like to add, e.g. Listen
        :param args: Values of the directive; list of str (eg. ["443"])
        :type args: list

        z	mod_ssl.cargr   Fzdirective[1]r   r   r   z
%s/arg[%d]N)	get_ifmodr%   insertrO   rG   r   )r:   r   r   r   if_mod_pathnvh_pathr   r   s           r;   add_dir_to_ifmodsslz ApacheParser.add_dir_to_ifmodssla  s     nn]K@e+[%@/Xy)t9>HHLLF*DG4#D/ D3\Xq1u,==sCDr=   r   c                     | j                   j                  |d|d      }|s| j                  ||      S |d   j                  d      d   S )a  Returns the path to <IfMod mod> and creates one if it doesn't exist.

        :param str aug_conf_path: Augeas configuration path
        :param str mod: module ie. mod_ssl.c
        :param bool beginning: If the IfModule should be created to the beginning
            of augeas path DOM tree.

        :returns: Augeas path of the requested IfModule directive that pre-existed
            or was created during the process. The path may be dynamic,
            i.e. .../IfModule[last()]
        :rtype: str

        z/IfModule/*[self::arg='z']r   r   )r%   rD   create_ifmod
rpartition)r:   r   r   if_modss       r;   r   zApacheParser.get_ifmod{  sR     ((..#0##7 9$$]C88 qz$$U+A..r=   c                     dj                  |      }dj                  |      }| j                  j                  |d       dj                  |      }| j                  j                  ||       |S )a>  Creates a new <IfMod mod> and returns its path.

        :param str aug_conf_path: Augeas configuration path
        :param str mod: module ie. mod_ssl.c

        :returns: Augeas path of the newly created IfModule directive.
            The path may be dynamic, i.e. .../IfModule[last()]
        :rtype: str

        z{}/IfModule[last() + 1]z{}/IfModule[last()]/argrU   z{}/IfModule[last()]/)rF   r%   rO   )r:   r   r   c_path
c_path_argretpaths         r;   r   zApacheParser.create_ifmod  s]     +11-@.55mD
VR (//>Z%r=   c                    |r|nd}| j                   j                  |dz   |       t        |t              r6t	        |d      D ]&  \  }}| j                   j                  d||fz  |       ( y| j                   j                  |dz   |       y)a  Appends directive to the end fo the file given by aug_conf_path.

        .. note:: Not added to AugeasConfigurator because it may depend
            on the lens

        :param str aug_conf_path: Augeas configuration path to add directive
        :param str directive: Directive to add
        :param args: Value of the directive. ie. Listen 443, 443 is arg
        :type args: list or str

        rU   z/directive[last() + 1]r   z%s/directive[last()]/arg[%d]z/directive[last()]/argN)r%   rO   
isinstancelistr   )r:   r   r   r   r   values         r;   rx   zApacheParser.add_dir  s     *7B]%==yIdD!%dA. P52mQ5GGPP HHLL)AA4Hr=   ry   c                    |r|nd}|dz   }| j                   j                  |      r| j                   j                  |dd       n| j                   j                  |d       | j                   j                  ||       t	        |t
              r7t        |d      D ]'  \  }}| j                   j                  |d|z  z   |       ) y| j                   j                  |dz   |       y)	a)  Adds the directive to the beginning of defined aug_conf_path.

        :param str aug_conf_path: Augeas configuration path to add directive
        :param str dirname: Directive to add
        :param args: Value of the directive. ie. Listen 443, 443 is arg
        :type args: list or str
        rU   z/directive[1]r   Tr   r   r   N)r%   rE   r   rO   r   r   r   )r:   r   ry   r   	first_dirr   r   s          r;   add_dir_beginningzApacheParser.add_dir_beginning  s     *7B!O3	88<<	"HHOOI{D9HHLLK0Y(dD!%dA. B5Yq)995AB HHLLV+T2r=   commentc                 B    | j                   j                  |dz   |       y)zAdds the comment to the augeas path

        :param str aug_conf_path: Augeas configuration path to add directive
        :param str comment: Comment content

        z/#comment[last() + 1]N)r%   rO   )r:   r   r   s      r;   add_commentzApacheParser.add_comment  s     	]%<<gFr=   r   startc                     |st        | j                        }| j                  j                  d|z        }g }|D ]6  }| j                  j	                  |      }|s!||v s&|j                  |       8 |S )a  Finds a comment with specified content from the provided DOM path

        :param str arg: Comment content to search
        :param str start: Beginning Augeas path to begin looking

        :returns: List of augeas paths containing the comment content
        :rtype: list

        z%s//*[label() = '#comment'])rw   r   r%   rD   rE   r|   )r:   r   r   commentsresultsr   	c_contents          r;   find_commentszApacheParser.find_comments  sp      +E88>>"?%"GH 	(GW-ISI-w'	( r=   excludec                    |st        | j                  d         }dt        |      dt        d      dt        d      d}| j                  j	                  |d|d      }|r| j                  |      }|d	}nd
t        |      z  }g }|D ]  }	| j                  j                  |	      j                         }
|
dv rD|j                  | j                  ||| j                  | j                  |	d	z               |             |
|j                         k(  s|j                  | j                  j	                  |	|z                 |S )a  Finds directive in the configuration.

        Recursively searches through config files to find directives
        Directives should be in the form of a case insensitive regex currently

        .. todo:: arg should probably be a list
        .. todo:: arg search currently only supports direct matching. It does
            not handle the case of variables or quoted arguments. This should
            be adapted to use a generic search for the directive and then do a
            case-insensitive self.get_arg filter

        Note: Augeas is inherently case sensitive while Apache is case
        insensitive.  Augeas 1.0 allows case insensitive regexes like
        regexp(/Listen/, "i"), however the version currently supported
        by Ubuntu 0.10 does not.  Thus I have included my own case insensitive
        transformation by calling case_i() on everything to maintain
        compatibility.

        :param str directive: Directive to look for
        :param arg: Specific value directive must have, None if all should
                    be considered
        :type arg: str or None

        :param str start: Beginning Augeas path to begin looking
        :param bool exclude: Whether or not to exclude directives based on
            variables and enabled modules

        :rtype list

        r   (z)|(rt   IncludeOptional)z//*[self::directive=~regexp('z')]r   z/*[self::arg=~regexp('%s')])includeincludeoptional)rw   r.   rv   r%   rD   exclude_dirsrE   lowerextendru   _get_include_pathr   )r:   r   r   r   r   regexrR   
arg_suffixordered_matchesrD   dir_s              r;   ru   zApacheParser.find_dir  s9   B  &!12E %+9$5$*9$5$*+<$=? ((..6;UCE ''0G;J6DJ%'  		KE88<<&,,.D55&&t}}s**4<<+GH( 
 y((&&txx~~ej6H'IJ		K r=   rD   c                 @   | j                   j                  |      }|sy|j                  d      }t        j                  j                  |      }|D ]%  }	 |j                  || j                  |dd          }' |S # t        $ r t        j                  d|z        w xY w)zUses augeas.get to get argument value and interprets result.

        This also converts all variables and parameters appropriately.

        N'"   r   zError Parsing variable: %s)r%   rE   r   r   r   findallreplacer*   KeyErrorr   rH   )r:   rD   r   r*   vars        r;   r   zApacheParser.get_arg?  s     U# E" 44<<UC	 	MCMc4>>#a)+DE	M   M(()E)KLLMs   "A;;"Bc                 2    t        | j                  d         S )z@
        Returns the Augeas path of root configuration.
        r   )rw   r.   ra   s    r;   get_root_augpathzApacheParser.get_root_augpath\  s     DHHV,--r=   c                     d| j                   j                         fd| j                  fg}g }|D ].  }|D ]  }| j                  ||      r  |j	                  |       0 |S )z>Exclude directives that are not loaded into the configuration.ifmoduleifdefine)r(   keysr*   _pass_filterr|   )r:   rR   filtersvalid_matchesrD   filter_s         r;   r   zApacheParser.exclude_dirsb  su     1 1 34z4>>6RS 	,E" ,((8, $$U+	, r=   r   c                 :   |j                         }|j                  |d         }|dk7  rr|j                  d|      }| j                  j                  |d| dz         }|j	                  d      r|dd |d   v r	y||d   vry|j                  |d   |      }|dk7  rry	)
zDetermine if directive passes a filter.

        :param str match: Augeas path
        :param list filter: list of tuples of form
            [("lowercase if directive", set of relevant parameters)]

        r   r   r#   Nr   !r   FT)r   findr%   rE   
startswith)r:   rD   r   match_llast_match_idx	end_of_if
expressions          r;   r   zApacheParser._pass_filterp  s     ++- gaj1"S.9IeJY&7&&@AJ$$S)ab>WQZ/ WQZ/ $\\'!*i@N "  r=   c                    |j                  d      }|j                  d      sIt        j                  j	                  t        j                  j                  | j                  |            }|S t        j                  j	                  |      }|S )zEnsure paths are consistent and absolute

        :param str arg: Argument of directive

        :returns: Standardized argument path
        :rtype: str
        r   r#   )r   r   r   r+   normpathrn   r   )r:   r   s     r;   standard_path_from_server_rootz+ApacheParser.standard_path_from_server_root  si     ii ~~c"''""277<<		3#?@C 
 ''""3'C
r=   c                    |y| j                  |      }t        j                  j                  |      r0| j	                  t        j                  j                  |d             n| j	                  |       |j                  d      }t        |      D ]/  \  }}t        d |D              sd| j                  |      z  ||<   1 dj                  |      }t        |      S )a@  Converts an Apache Include directive into Augeas path.

        Converts an Apache Include directive argument into an Augeas
        searchable path

        .. todo:: convert to use os.path.join()

        :param str arg: Argument of Include directive

        :returns: Augeas path string
        :rtype: str

        Nr   r#   c              3   @   K   | ]  }|t         j                  v   y wN)r   r   )rh   chars     r;   rj   z1ApacheParser._get_include_path.<locals>.<genexpr>  s     H$4<555Hs   z* [label()=~regexp('%s')])r   r   r+   isdirr/   rn   splitr   anyfnmatch_to_rerw   )r:   r   	split_argidxr  s        r;   r   zApacheParser._get_include_path  s    ( ;11#6 77==OOBGGLLc23OOC 
 IIcN	#I. 	=JCH%HH #>"&"4"4U";#<	#		= hhy!C  r=   clean_fn_matchc                 2    t        j                  |      dd S )a  Method converts Apache's basic fnmatch to regular expression.

        Assumption - Configs are assumed to be well-formed and only writable by
        privileged users.

        https://apr.apache.org/docs/apr/2.0/apr__fnmatch_8h_source.html

        :param str clean_fn_match: Apache style filename match, like globs

        :returns: regex suitable for augeas
        :rtype: str

           )fnmatch	translate)r:   r  s     r;   r  zApacheParser.fnmatch_to_re  s       0266r=   filepathc                    | j                  |      \  }}| j                          |r`| j                  j                  d|z        }|s?|r| j	                  |       | j                  |       | j                  j                          yyy)zParse file with Augeas

        Checks to see if file_path is parsed by Augeas
        If filepath isn't parsed, the file is added and Augeas is reloaded

        :param str filepath: Apache config file path

        z&/augeas/load/Httpd['%s' =~ glob(incl)]N)_check_path_actionsrb   r%   rD   _remove_httpd_transform_add_httpd_transformrd   )r:   r  use_new
remove_oldinc_tests        r;   r/   zApacheParser.parse_file  s     #66x@ 	  " xx~~88CEH 00:))(3  r=   filepc                 @    |sy| j                  || j                        S )a<  Checks if the file path is parsed by current Augeas parser config
        ie. returns True if the file is found on a path that's found in live
        Augeas configuration.

        :param str filep: Path to match

        :returns: True if file is parsed in existing configuration tree
        :rtype: bool
        F)_parsed_by_parser_pathsr)   r:   r  s     r;   r   zApacheParser.parsed_in_current  s#     ++E43D3DEEr=   c                 @    |sy| j                  || j                        S )a[  Checks if the file path is parsed by existing Apache config.
        ie. returns True if the file is found on a path that matches Include or
        IncludeOptional statement in the Apache configuration.

        :param str filep: Path to match

        :returns: True if file is parsed in existing configuration tree
        :rtype: bool
        F)r  r7   r  s     r;   parsed_in_originalzApacheParser.parsed_in_original  s#     ++E43F3FGGr=   pathsc           	          |D ]C  }||   D ]9  }t        j                   |t        j                  j                  ||            s8  y E y)znHelper function that searches through provided paths and returns
        True if file path is found in the setTF)r
  r   r+   rn   )r:   r  r  	directoryfilenames        r;   r  z$ApacheParser._parsed_by_parser_paths  sL      	 I!),  ??5"'',,y(*KL 	  r=   c                     	 t         j                  j                  |      }| j                  t         j                  j	                  |         }d|v rd}nd}|dk(  }||fS # t
        $ r
 d}d}Y ||fS w xY w)aL  Determine actions to take with a new augeas path

        This helper function will return a tuple that defines
        if we should try to append the new filepath to augeas
        parser paths, and / or remove the old one with more
        narrow matching.

        :param str filepath: filepath to check the actions for

        r   FT)r   r+   rz   r)   ry   r   )r:   r  new_file_matchexisting_matchesr  r  s         r;   r  z ApacheParser._check_path_actions  s    
	WW--h7N#001JK&&'3.J 
""  	GJ
""	s   AA A21A2c                 f   | j                   t        j                  j                  |         }t        j                  j                  |      }|D ]F  }|dz   |z   }| j                  j                  d|z        }| j                  j                  |d          H | j                   j                  |       y)z[Remove path from Augeas transform

        :param str filepath: filepath to remove
        r#   z!/augeas/load/Httpd/incl [. ='%s']r   N)r)   r   r+   ry   r%   rD   rQ   pop)r:   r  remove_basenamesremove_dirnamenameremove_path
remove_incs          r;   r  z$ApacheParser._remove_httpd_transform8  s      ,,RWW__X-FG2$ 	+D(3.5K3kACJHHOOJqM*		+
 	n-r=   inclc                    | j                   j                  d      }|r=| j                   j                  |d   dd       | j                   j                  d|       n8| j                   j                  dd       | j                   j                  d|       	 | j                  t
        j                  j                  |         j                  t
        j                  j                  |             y	# t        $ rM t
        j                  j                  |      g| j                  t
        j                  j                  |      <   Y y	w xY w)
a"  Add a transform to Augeas.

        This function will correctly add a transform to augeas
        The existing augeas.add_transform in python doesn't seem to work for
        Travis CI as it loads in libaugeas.so.0.10.0

        :param str incl: filepath to include for transform

        z /augeas/load/Httpd/incl [last()]r   r(  Fz/augeas/load/Httpd/incl[last()]z/augeas/load/Httpd/lensz	Httpd.lnsz/augeas/load/Httpd/inclN)r%   rD   r   rO   r)   r   r+   ry   r|   rz   r   )r:   r(  last_includes      r;   r  z!ApacheParser._add_httpd_transformG  s     !HHNN+MNHHOOLOVU;HHLL:DA HHLL2K@HHLL2D9	(bggood34;;  &( 	(  &8(Dbggood34	(s   AC- -AEEc                 \   ddddddddd	| j                   d
z   | j                   dz   | j                   dz   | j                   dz   | j                   dz   | j                   dz   g}t        |d      D ]$  \  }}| j                  j                  d|z  |       & | j                  j	                          y)aa  Standardize the excl arguments for the Httpd lens in Augeas.

        Note: Hack!
        Standardize the excl arguments for the Httpd lens in Augeas
        Servers sometimes give incorrect defaults
        Note: This problem should be fixed in Augeas 1.0.  Unfortunately,
        Augeas 0.10 appears to be the most popular version currently.

        z*.augnewz	*.augsavez*.dpkg-distz
*.dpkg-bakz
*.dpkg-newz
*.dpkg-oldz	*.rpmsavez*.rpmnewz*~z
/*.augsavez/*~z/*/*augsavez/*/*~z/*/*/*.augsavez/*/*/*~r   z/augeas/load/Httpd/excl[%d]N)r   r   r%   rO   rd   )r:   exclr   excludeds       r;   r1   zApacheParser.standardize_exclc  s    " KlK		L(		E!		M)		G#		,,		I%' %T1- 	FKAxHHLL6:HE	F 	r=   c                     | j                   d   }t        j                  j                  | j                  d      }t        j                  j                  |      r|}|}n|}|}|||dS )zSet default location for directives.

        Locations are given as file_paths
        .. todo:: Make sure that files are included

        r   z
ports.conf)defaultlistenr%  )r.   r   r+   rn   r   isfile)r:   r/  tempr0  r%  s        r;   r4   zApacheParser._set_locations  s[     xx'GGLLL977>>$FDFD"fdCCr=   c                 (   g d}|D ]u  }t         j                  j                  t         j                  j                  | j                  |            sKt         j                  j                  | j                  |      c S  t        j                  d      )z(Find the Apache Configuration Root file.)zapache2.confz
httpd.confzconf/httpd.confz!Could not find configuration root)r   r+   r1  rn   r   r   NoInstallationError)r:   locationr%  s      r;   r-   zApacheParser._find_config_root  sf    D 	5Dww~~bggll499d;<ww||DIIt44	5 (()LMMr=   ))r   r  )r!   Nr   )NNT)?__name__
__module____qualname____doc__recompiler   r	   __annotations__r   r
   strr   intr<   rL   r   boolr   r&   r_   rb   r   rV   rX   r   r   r   r2   r0   r   r   r   r   r   r   r   r   rx   r   r   r   ru   r   r   r   r   r   r   r   r  r/   r   r  r   r  r  r  r  r1   r   r4   r-    r=   r;   r   r   "   s2   
 $.2::o#>>8M3s88 =C-CS -C0D -C-C*/S/-CGK-C^. . .45tCy#9 %s3x %N%x}  2d d$ d"Is Ic Id I&: : :"8^'&s # $s) >D D DDQTI DZ^ D4/s / / /,# C C $I%c]I7?}ILQRVWZR[]`R`LaI	I.3x} 3s 3 %d3in 53:>3.G Gs Gt G Xc] d3i , =A>BM# MHSM M M7;MGKCyM^S Xc] :.# .HSM d3i # c:c?6J0K PT :# # &,!Xc] ,!x} ,!\7C 7C 7" 3  4  6Fx} F FH H$ HS d3i9P UY #C #E$*4E #2. . .( ( (8@DS#X D&N3 Nr=   r   stringr!   c                 X    dj                  d t        j                  |       D              S )a`  Returns case insensitive regex.

    Returns a sloppy, but necessary version of a case insensitive regex.
    Any string should be able to be submitted and the string is
    escaped and then made case insensitive.
    May be replaced by a more proper /i once augeas 1.0 is widely
    supported.

    :param str string: string to make case i regex

    rU   c              3      K   | ]=  }|j                         r'd |j                         z   |j                         z   dz   n| ? yw)r   r   N)isalphaupperr   )rh   r   s     r;   rj   zcase_i.<locals>.<genexpr>  sD      F./qyy{ ?QWWY.4()* Fs   AA)rn   r:  escape)rA  s    r;   rv   rv     s/     77 F3599V3DF F Fr=   	file_pathc                     d| z  S )zTReturn augeas path for full filepath.

    :param str file_path: Full filepath

    z/files%sr@  )rG  s    r;   rw   rw     s     	!!r=   c                      t         st        j                  d      t        t        j                  t         j
                  t         j                  z  t         j                  z        S )z' Initialize the actual Augeas instance zProblem in Augeas installation)loadpathflags)r   r   r4  r   AUGEAS_LENS_DIRNONENO_MODL_AUTOLOADENABLE_SPANr@  r=   r;   r$   r$     sT     (()IJJ** {{&&'!!"$ $r=   )%r9  r5   r
  loggingr:  typingr   r   r   r   r   r   r	   r
   r   r   r   certbotr   certbot.compatr   certbot_apache._internalr   r   %certbot_apache._internal.configuratorr   augeasr   ImportError	getLoggerr6  rk   r   r=  rv   rw   r$   r@  r=   r;   <module>rY     s    F    	               0 .H 
		8	$zN zNzF3 F3 F "C "C "$V $y  Fs   6B/ /B98B9