Class: BetterHtml::TestHelper::SafeLodashTester::Tester

Inherits:
Object
  • Object
show all
Defined in:
lib/better_html/test_helper/safe_lodash_tester.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(buffer, config: BetterHtml.config) ⇒ Tester

Returns a new instance of Tester.



55
56
57
58
59
60
61
# File 'lib/better_html/test_helper/safe_lodash_tester.rb', line 55

def initialize(buffer, config: BetterHtml.config)
  @buffer = buffer
  @config = config
  @errors = Errors.new
  @parser = BetterHtml::Parser.new(buffer, template_language: :lodash)
  validate!
end

Instance Attribute Details

#errorsObject (readonly)

Returns the value of attribute errors.



53
54
55
# File 'lib/better_html/test_helper/safe_lodash_tester.rb', line 53

def errors
  @errors
end

Instance Method Details

#add_error(message, location:) ⇒ Object



63
64
65
# File 'lib/better_html/test_helper/safe_lodash_tester.rb', line 63

def add_error(message, location:)
  @errors.add(SafetyError.new(message, location: location))
end

#add_no_statement_error(loc) ⇒ Object



132
133
134
135
136
137
# File 'lib/better_html/test_helper/safe_lodash_tester.rb', line 132

def add_no_statement_error(loc)
  add_error(
    "javascript statement not allowed here; did you mean '[%=' ?",
    location: loc,
  )
end

#lodash_nodes(node) ⇒ Object



86
87
88
89
90
91
92
93
94
95
# File 'lib/better_html/test_helper/safe_lodash_tester.rb', line 86

def lodash_nodes(node)
  Enumerator.new do |yielder|
    next if node.nil?

    node.descendants(:lodash).each do |lodash_node|
      indicator_node, code_node = *lodash_node
      yielder.yield(lodash_node, indicator_node, code_node)
    end
  end
end

#validate!Object



67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/better_html/test_helper/safe_lodash_tester.rb', line 67

def validate!
  @parser.nodes_with_type(:tag).each do |tag_node|
    tag = Tree::Tag.from_node(tag_node)
    validate_tag_attributes(tag)
    validate_no_statements(tag_node)

    next unless tag.name == "script" && !tag.closing?

    add_error(
      "No script tags allowed nested in lodash templates",
      location: tag_node.loc,
    )
  end

  @parser.nodes_with_type(:cdata, :comment).each do |node|
    validate_no_statements(node)
  end
end

#validate_no_statements(node) ⇒ Object



126
127
128
129
130
# File 'lib/better_html/test_helper/safe_lodash_tester.rb', line 126

def validate_no_statements(node)
  lodash_nodes(node).each do |lodash_node, indicator_node, _code_node|
    add_no_statement_error(lodash_node.loc) if indicator_node.nil?
  end
end

#validate_tag_attributes(tag) ⇒ Object



97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/better_html/test_helper/safe_lodash_tester.rb', line 97

def validate_tag_attributes(tag)
  tag.attributes.each do |attribute|
    lodash_nodes(attribute.value_node).each do |lodash_node, indicator_node, _code_node|
      next if indicator_node.nil?

      if indicator_node.loc.source == "="
        validate_tag_expression(attribute, lodash_node)
      elsif indicator_node.loc.source == "!"
        add_error(
          "lodash interpolation with '[%!' inside html attribute is never safe",
          location: lodash_node.loc,
        )
      end
    end
  end
end

#validate_tag_expression(attribute, lodash_node) ⇒ Object



114
115
116
117
118
119
120
121
122
123
124
# File 'lib/better_html/test_helper/safe_lodash_tester.rb', line 114

def validate_tag_expression(attribute, lodash_node)
  _, code_node = *lodash_node
  source = code_node.loc.source.strip
  if @config.javascript_attribute_name?(attribute.name) && !@config.lodash_safe_javascript_expression?(source)
    add_error(
      "lodash interpolation in javascript attribute " \
        "`#{attribute.name}` must call `JSON.stringify(#{source})`",
      location: lodash_node.loc,
    )
  end
end