def visit_BinOp(self, node): """ Checks for concat using '+' and interpolation using '%' with strings containing HTML. """ rule = None if isinstance(node.op, ast.Mod): rule = ruleset.python_interpolate_html elif isinstance(node.op, ast.Add): rule = ruleset.python_concat_html if rule is not None: visitor = HtmlStringVisitor(self.file_contents, self.results) visitor.visit(node.left) has_illegal_html_string = len(visitor.unsafe_html_string_nodes) > 0 # Create new visitor to clear state. visitor = HtmlStringVisitor(self.file_contents, self.results) visitor.visit(node.right) has_illegal_html_string = has_illegal_html_string or len( visitor.unsafe_html_string_nodes) > 0 if has_illegal_html_string: self.results.violations.append( ExpressionRuleViolation(rule, self.node_to_expression(node))) self.generic_visit(node)
def visit_Attribute(self, node): """ Checks for uses of deprecated `display_name_with_default_escaped`. Arguments: node: An AST node. """ if node.attr == 'display_name_with_default_escaped': self.results.violations.append( ExpressionRuleViolation(ruleset.python_deprecated_display_name, self.node_to_expression(node))) self.generic_visit(node)
def visit_Call(self, node): """ Checks for a variety of violations: - Checks that format() calls with nested HTML() or Text() calls use HTML() or Text() on the left-hand side. - For each HTML() and Text() call, calls into separate visitor to check for inner format() calls. Arguments: node: An AST node. """ if isinstance(node.func, ast.Attribute) and node.func.attr == 'format': visitor = FormatInterpolateVisitor(self.file_contents, self.results) visitor.visit(node) if visitor.interpolates_text_or_html: format_caller = node.func.value is_caller_html_or_text = isinstance(format_caller, ast.Call) and \ isinstance(format_caller.func, ast.Name) and \ format_caller.func.id in ['Text', 'HTML'] # If format call has nested Text() or HTML(), then the caller, # or left-hand-side of the format() call, must be a call to # Text() or HTML(). if is_caller_html_or_text is False: self.results.violations.append( ExpressionRuleViolation( ruleset.python_requires_html_or_text, self.node_to_expression(node.func))) elif isinstance(node.func, ast.Name) and node.func.id in ['HTML', 'Text']: visitor = ContainsFormatVisitor(self.file_contents, self.results) visitor.visit(node) if visitor.contains_format_call: self.results.violations.append( ExpressionRuleViolation(ruleset.python_close_before_format, self.node_to_expression( node.func))) self.generic_visit(node)
def visit_Call(self, node): """ Checks that format() calls which contain HTML() or Text() use HTML() or Text() as the caller. In other words, Text() or HTML() must be used before format() for any arguments to format() that contain HTML() or Text(). Arguments: node: An AST node. """ if isinstance(node.func, ast.Attribute) and node.func.attr == 'format': visitor = HtmlStringVisitor(self.file_contents, self.results, True) visitor.visit(node) for unsafe_html_string_node in visitor.unsafe_html_string_nodes: self.results.violations.append( ExpressionRuleViolation( ruleset.python_wrap_html, self.node_to_expression(unsafe_html_string_node))) # Do not continue processing child nodes of this format() node. else: self.generic_visit(node)
def _add_violations(results, rule_violation, self): results.violations.append(ExpressionRuleViolation(rule_violation, self))