2019-11-15 05:22:18 -05:00
|
|
|
""" apacheconfig implementation of the ParserNode interfaces """
|
|
|
|
|
|
2019-12-06 20:41:21 -05:00
|
|
|
from functools import partial
|
|
|
|
|
|
2020-01-21 20:14:30 -05:00
|
|
|
from certbot import errors
|
|
|
|
|
|
2020-01-06 10:19:33 -05:00
|
|
|
from certbot_apache._internal import assertions
|
|
|
|
|
from certbot_apache._internal import interfaces
|
|
|
|
|
from certbot_apache._internal import parsernode_util as util
|
2019-11-15 05:22:18 -05:00
|
|
|
|
|
|
|
|
|
|
|
|
|
class ApacheParserNode(interfaces.ParserNode):
|
|
|
|
|
""" apacheconfig implementation of ParserNode interface.
|
|
|
|
|
|
|
|
|
|
Expects metadata `ac_ast` to be passed in, where `ac_ast` is the AST provided
|
|
|
|
|
by parsing the equivalent configuration text using the apacheconfig library.
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
def __init__(self, **kwargs):
|
|
|
|
|
ancestor, dirty, filepath, metadata = util.parsernode_kwargs(kwargs) # pylint: disable=unused-variable
|
|
|
|
|
super(ApacheParserNode, self).__init__(**kwargs)
|
|
|
|
|
self.ancestor = ancestor
|
|
|
|
|
self.filepath = filepath
|
|
|
|
|
self.dirty = dirty
|
|
|
|
|
self.metadata = metadata
|
|
|
|
|
self._raw = self.metadata["ac_ast"]
|
|
|
|
|
|
|
|
|
|
def save(self, msg): # pragma: no cover
|
|
|
|
|
pass
|
|
|
|
|
|
2019-12-02 09:25:39 -05:00
|
|
|
def find_ancestors(self, name): # pylint: disable=unused-variable
|
|
|
|
|
"""Find ancestor BlockNodes with a given name"""
|
|
|
|
|
return [ApacheBlockNode(name=assertions.PASS,
|
|
|
|
|
parameters=assertions.PASS,
|
|
|
|
|
ancestor=self,
|
|
|
|
|
filepath=assertions.PASS,
|
|
|
|
|
metadata=self.metadata)]
|
|
|
|
|
|
2019-11-15 05:22:18 -05:00
|
|
|
|
|
|
|
|
class ApacheCommentNode(ApacheParserNode):
|
|
|
|
|
""" apacheconfig implementation of CommentNode interface """
|
|
|
|
|
|
|
|
|
|
def __init__(self, **kwargs):
|
|
|
|
|
comment, kwargs = util.commentnode_kwargs(kwargs) # pylint: disable=unused-variable
|
|
|
|
|
super(ApacheCommentNode, self).__init__(**kwargs)
|
|
|
|
|
self.comment = comment
|
|
|
|
|
|
|
|
|
|
def __eq__(self, other): # pragma: no cover
|
|
|
|
|
if isinstance(other, self.__class__):
|
|
|
|
|
return (self.comment == other.comment and
|
|
|
|
|
self.dirty == other.dirty and
|
|
|
|
|
self.ancestor == other.ancestor and
|
|
|
|
|
self.metadata == other.metadata and
|
|
|
|
|
self.filepath == other.filepath)
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ApacheDirectiveNode(ApacheParserNode):
|
|
|
|
|
""" apacheconfig implementation of DirectiveNode interface """
|
|
|
|
|
|
|
|
|
|
def __init__(self, **kwargs):
|
|
|
|
|
name, parameters, enabled, kwargs = util.directivenode_kwargs(kwargs)
|
|
|
|
|
super(ApacheDirectiveNode, self).__init__(**kwargs)
|
|
|
|
|
self.name = name
|
|
|
|
|
self.parameters = parameters
|
|
|
|
|
self.enabled = enabled
|
|
|
|
|
self.include = None
|
|
|
|
|
|
|
|
|
|
def __eq__(self, other): # pragma: no cover
|
|
|
|
|
if isinstance(other, self.__class__):
|
|
|
|
|
return (self.name == other.name and
|
|
|
|
|
self.filepath == other.filepath and
|
|
|
|
|
self.parameters == other.parameters and
|
|
|
|
|
self.enabled == other.enabled and
|
|
|
|
|
self.dirty == other.dirty and
|
|
|
|
|
self.ancestor == other.ancestor and
|
|
|
|
|
self.metadata == other.metadata)
|
|
|
|
|
return False
|
|
|
|
|
|
2020-01-06 10:19:33 -05:00
|
|
|
def set_parameters(self, _parameters):
|
2019-11-15 05:22:18 -05:00
|
|
|
"""Sets the parameters for DirectiveNode"""
|
2020-01-06 10:19:33 -05:00
|
|
|
return
|
2019-11-15 05:22:18 -05:00
|
|
|
|
|
|
|
|
|
2019-12-06 20:40:56 -05:00
|
|
|
def _parameters_from_string(text):
|
|
|
|
|
text = text.strip()
|
|
|
|
|
words = []
|
|
|
|
|
word = ""
|
|
|
|
|
quote = None
|
|
|
|
|
escape = False
|
|
|
|
|
for c in text:
|
|
|
|
|
if c.isspace() and not quote:
|
|
|
|
|
if word:
|
|
|
|
|
words.append(word)
|
|
|
|
|
word = ""
|
|
|
|
|
else:
|
|
|
|
|
word += c
|
|
|
|
|
if not escape:
|
|
|
|
|
if not quote and c in "\"\'":
|
|
|
|
|
quote = c
|
|
|
|
|
elif c == quote:
|
|
|
|
|
words.append(word[1:-1])
|
|
|
|
|
word = ""
|
|
|
|
|
quote = None
|
|
|
|
|
escape = c == "\\"
|
|
|
|
|
if word:
|
|
|
|
|
words.append(word)
|
|
|
|
|
return tuple(words)
|
|
|
|
|
|
|
|
|
|
|
2019-11-15 05:22:18 -05:00
|
|
|
class ApacheBlockNode(ApacheDirectiveNode):
|
|
|
|
|
""" apacheconfig implementation of BlockNode interface """
|
|
|
|
|
|
|
|
|
|
def __init__(self, **kwargs):
|
|
|
|
|
super(ApacheBlockNode, self).__init__(**kwargs)
|
2019-12-06 20:40:56 -05:00
|
|
|
self._raw_children = self._raw
|
|
|
|
|
children = []
|
|
|
|
|
for raw_node in self._raw_children:
|
|
|
|
|
metadata = self.metadata.copy()
|
|
|
|
|
metadata['ac_ast'] = raw_node
|
|
|
|
|
if raw_node.typestring == "comment":
|
|
|
|
|
node = ApacheCommentNode(comment=raw_node.name[2:],
|
|
|
|
|
metadata=metadata, ancestor=self,
|
|
|
|
|
filepath=self.filepath)
|
|
|
|
|
elif raw_node.typestring == "block":
|
|
|
|
|
parameters = _parameters_from_string(raw_node.arguments)
|
|
|
|
|
node = ApacheBlockNode(name=raw_node.tag, parameters=parameters,
|
|
|
|
|
metadata=metadata, ancestor=self,
|
|
|
|
|
filepath=self.filepath, enabled=self.enabled)
|
|
|
|
|
else:
|
|
|
|
|
parameters = ()
|
|
|
|
|
if raw_node.value:
|
|
|
|
|
parameters = _parameters_from_string(raw_node.value)
|
|
|
|
|
node = ApacheDirectiveNode(name=raw_node.name, parameters=parameters,
|
|
|
|
|
metadata=metadata, ancestor=self,
|
|
|
|
|
filepath=self.filepath, enabled=self.enabled)
|
|
|
|
|
children.append(node)
|
|
|
|
|
self.children = tuple(children)
|
2019-11-15 05:22:18 -05:00
|
|
|
|
|
|
|
|
def __eq__(self, other): # pragma: no cover
|
|
|
|
|
if isinstance(other, self.__class__):
|
|
|
|
|
return (self.name == other.name and
|
|
|
|
|
self.filepath == other.filepath and
|
|
|
|
|
self.parameters == other.parameters and
|
|
|
|
|
self.children == other.children and
|
|
|
|
|
self.enabled == other.enabled and
|
|
|
|
|
self.dirty == other.dirty and
|
|
|
|
|
self.ancestor == other.ancestor and
|
|
|
|
|
self.metadata == other.metadata)
|
|
|
|
|
return False
|
|
|
|
|
|
2019-12-06 20:41:21 -05:00
|
|
|
def _add_child_thing(self, raw_string, partial_node, position):
|
|
|
|
|
position = len(self._raw_children) if not position else position
|
|
|
|
|
# Cap position to length to mimic AugeasNode behavior. TODO: document that this happens
|
|
|
|
|
position = min(len(self._raw_children), position)
|
|
|
|
|
raw_ast = self._raw_children.add(position, raw_string)
|
|
|
|
|
metadata = self.metadata.copy()
|
|
|
|
|
metadata['ac_ast'] = raw_ast
|
|
|
|
|
new_node = partial_node(ancestor=self, metadata=metadata, filepath=self.filepath)
|
|
|
|
|
|
|
|
|
|
# Update metadata
|
|
|
|
|
children = list(self.children)
|
|
|
|
|
children.insert(position, new_node)
|
|
|
|
|
self.children = tuple(children)
|
|
|
|
|
return new_node
|
|
|
|
|
|
|
|
|
|
def add_child_block(self, name, parameters=None, position=None):
|
2019-11-15 05:22:18 -05:00
|
|
|
"""Adds a new BlockNode to the sequence of children"""
|
2019-12-06 20:41:21 -05:00
|
|
|
parameters_str = " " + " ".join(parameters) if parameters else ""
|
|
|
|
|
if not parameters:
|
|
|
|
|
parameters = []
|
2020-01-21 20:14:30 -05:00
|
|
|
partial_block = partial(ApacheBlockNode, name=name,
|
|
|
|
|
parameters=tuple(parameters), enabled=self.enabled)
|
|
|
|
|
return self._add_child_thing("\n<%s%s>\n</%s>" % (name, parameters_str, name),
|
|
|
|
|
partial_block, position)
|
2019-11-15 05:22:18 -05:00
|
|
|
|
2019-12-06 20:41:21 -05:00
|
|
|
def add_child_directive(self, name, parameters=None, position=None):
|
2019-11-15 05:22:18 -05:00
|
|
|
"""Adds a new DirectiveNode to the sequence of children"""
|
2019-12-06 20:41:21 -05:00
|
|
|
parameters_str = " " + " ".join(parameters) if parameters else ""
|
2020-01-21 20:14:30 -05:00
|
|
|
if not parameters: # TODO (mona): test
|
|
|
|
|
parameters = [] # pragma: no cover
|
|
|
|
|
partial_block = partial(ApacheDirectiveNode, name=name,
|
|
|
|
|
parameters=tuple(parameters), enabled=self.enabled)
|
2019-12-06 20:41:21 -05:00
|
|
|
return self._add_child_thing("\n%s%s" % (name, parameters_str), partial_block, position)
|
2019-11-15 05:22:18 -05:00
|
|
|
|
2019-12-06 20:41:21 -05:00
|
|
|
def add_child_comment(self, comment="", position=None):
|
2019-11-15 05:22:18 -05:00
|
|
|
"""Adds a new CommentNode to the sequence of children"""
|
2019-12-06 20:41:21 -05:00
|
|
|
partial_comment = partial(ApacheCommentNode, comment=comment)
|
|
|
|
|
return self._add_child_thing(comment, partial_comment, position)
|
2019-11-15 05:22:18 -05:00
|
|
|
|
|
|
|
|
def find_blocks(self, name, exclude=True): # pylint: disable=unused-argument
|
|
|
|
|
"""Recursive search of BlockNodes from the sequence of children"""
|
|
|
|
|
return [ApacheBlockNode(name=assertions.PASS,
|
|
|
|
|
parameters=assertions.PASS,
|
|
|
|
|
ancestor=self,
|
|
|
|
|
filepath=assertions.PASS,
|
|
|
|
|
metadata=self.metadata)]
|
|
|
|
|
|
|
|
|
|
def find_directives(self, name, exclude=True): # pylint: disable=unused-argument
|
|
|
|
|
"""Recursive search of DirectiveNodes from the sequence of children"""
|
|
|
|
|
return [ApacheDirectiveNode(name=assertions.PASS,
|
|
|
|
|
parameters=assertions.PASS,
|
|
|
|
|
ancestor=self,
|
|
|
|
|
filepath=assertions.PASS,
|
|
|
|
|
metadata=self.metadata)]
|
|
|
|
|
|
|
|
|
|
def find_comments(self, comment, exact=False): # pylint: disable=unused-argument
|
|
|
|
|
"""Recursive search of DirectiveNodes from the sequence of children"""
|
|
|
|
|
return [ApacheCommentNode(comment=assertions.PASS,
|
|
|
|
|
ancestor=self,
|
|
|
|
|
filepath=assertions.PASS,
|
|
|
|
|
metadata=self.metadata)]
|
|
|
|
|
|
2020-01-21 20:14:30 -05:00
|
|
|
# TODO (mona): test
|
|
|
|
|
def delete_child(self, child): # pragma: no cover
|
2019-11-15 05:22:18 -05:00
|
|
|
"""Deletes a ParserNode from the sequence of children"""
|
2019-12-06 20:38:35 -05:00
|
|
|
index = -1
|
|
|
|
|
i = None
|
|
|
|
|
for i, elem in enumerate(self.children):
|
|
|
|
|
if elem == child:
|
|
|
|
|
index = i
|
|
|
|
|
break
|
|
|
|
|
if index < 0:
|
|
|
|
|
raise errors.PluginError("Could not find child node to delete")
|
|
|
|
|
children_list = list(self.children)
|
|
|
|
|
thing = children_list.pop(i)
|
|
|
|
|
self.children = tuple(children_list)
|
|
|
|
|
self._raw_children.remove(i)
|
|
|
|
|
return thing
|
2019-11-15 05:22:18 -05:00
|
|
|
|
|
|
|
|
def unsaved_files(self): # pragma: no cover
|
|
|
|
|
"""Returns a list of unsaved filepaths"""
|
|
|
|
|
return [assertions.PASS]
|
|
|
|
|
|
2019-12-10 13:20:00 -05:00
|
|
|
def parsed_paths(self): # pragma: no cover
|
|
|
|
|
"""Returns a list of parsed configuration file paths"""
|
|
|
|
|
return [assertions.PASS]
|
|
|
|
|
|
2019-11-15 05:22:18 -05:00
|
|
|
|
|
|
|
|
interfaces.CommentNode.register(ApacheCommentNode)
|
|
|
|
|
interfaces.DirectiveNode.register(ApacheDirectiveNode)
|
|
|
|
|
interfaces.BlockNode.register(ApacheBlockNode)
|