Module: Brakeman::RenderHelper

Included in:
ControllerAliasProcessor, SlimTemplateProcessor, TemplateAliasProcessor
Defined in:
lib/brakeman/processors/lib/render_helper.rb

Overview

Processes a call to render() in a controller or template

Instance Method Summary collapse

Instance Method Details

#get_class_target(sexp) ⇒ Object


176
177
178
179
180
181
182
183
184
185
186
187
# File 'lib/brakeman/processors/lib/render_helper.rb', line 176

def get_class_target sexp
  if call? sexp
    get_class_target sexp.target
  else
    klass = class_name sexp
    if klass.is_a? Symbol
      klass
    else
      nil
    end
  end
end

#get_options(args) ⇒ Object

Turn options Sexp into hash


163
164
165
166
167
168
169
170
171
172
173
174
# File 'lib/brakeman/processors/lib/render_helper.rb', line 163

def get_options args
  options = {}
  return options unless hash? args

  hash_iterate args do |key, value|
    if symbol? key
      options[key.value] = value
    end
  end

  options
end

#process_action(name, args, line) ⇒ Object

Processes a given action


49
50
51
52
53
# File 'lib/brakeman/processors/lib/render_helper.rb', line 49

def process_action name, args, line
  if name.is_a? String or name.is_a? Symbol
    process_template template_name(name), args, nil, line
  end
end

#process_layout(name = nil) ⇒ Object

Processes layout


27
28
29
30
31
32
33
34
35
# File 'lib/brakeman/processors/lib/render_helper.rb', line 27

def process_layout name = nil
  if name.nil? and defined? layout_name
    name = layout_name
  end

  return unless name

  process_template name, nil, nil, nil
end

#process_partial(name, args, line) ⇒ Object

Determines file name for partial and then processes it


38
39
40
41
42
43
44
45
46
# File 'lib/brakeman/processors/lib/render_helper.rb', line 38

def process_partial name, args, line
  if !(string? name or symbol? name) or name.value == ""
    return
  end

  names = name.value.to_s.split("/")
  names[-1] = "_" + names[-1]
  process_template template_name(names.join("/")), args, nil, line
end

#process_render(exp) ⇒ Object

Process s(:render, TYPE, OPTION?, OPTIONS)


7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# File 'lib/brakeman/processors/lib/render_helper.rb', line 7

def process_render exp
  process_default exp
  @rendered = true
  case exp.render_type
  when :action, :template, :inline
    process_action exp[2][1], exp[3], exp.line
  when :default
    begin
      process_template template_name, exp[3], nil, exp.line
    rescue ArgumentError
      Brakeman.debug "Problem processing render: #{exp}"
    end
  when :partial, :layout
    process_partial exp[2], exp[3], exp.line
  when :nothing
  end
  exp
end

#process_template(name, args, called_from = nil, *_) ⇒ Object

Processes a template, adding any instance variables to its environment.


57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
# File 'lib/brakeman/processors/lib/render_helper.rb', line 57

def process_template name, args, called_from = nil, *_

  Brakeman.debug "Rendering #{name} (#{called_from})"
  #Get scanned source for this template
  name = name.to_s.gsub(/^\//, "")
  template = @tracker.templates[name.to_sym]
  unless template
    Brakeman.debug "[Notice] No such template: #{name}"
    return
  end

  if called_from
    # Track actual template that was rendered
    called_from.last_template = template
  end

  template_env = only_ivars(:include_request_vars)

  #Hash the environment and the source of the template to avoid
  #pointlessly processing templates, which can become prohibitively
  #expensive in terms of time and memory.
  digest = Digest::SHA1.new.update(template_env.instance_variable_get(:@env).to_a.sort.to_s << name).to_s.to_sym

  if @tracker.template_cache.include? digest
    #Already processed this template with identical environment
    return
  else
    @tracker.template_cache << digest

    options = get_options args

    #Process layout
    if string? options[:layout]
      process_template "layouts/#{options[:layout][1]}", nil, nil, nil
    elsif node_type? options[:layout], :false
      #nothing
    elsif not template.name.to_s.match(/[^\/_][^\/]+$/)
      #Don't do this for partials

      process_layout
    end

    if hash? options[:locals]
      hash_iterate options[:locals] do |key, value|
        if symbol? key
          template_env[Sexp.new(:call, nil, key.value)] = value
        end
      end
    end

    if options[:collection]

      #The collection name is the name of the partial without the leading
      #underscore.
      variable = template.name.to_s.match(/[^\/_][^\/]+$/)[0].to_sym

      #Unless the :as => :variable_name option is used
      if options[:as]
        if string? options[:as] or symbol? options[:as]
          variable = options[:as].value.to_sym
        end
      end

      collection = get_class_target(options[:collection]) || Brakeman::Tracker::UNKNOWN_MODEL

      template_env[Sexp.new(:call, nil, variable)] = Sexp.new(:call, Sexp.new(:const, collection), :new)
    end

    #Set original_line for values so it is clear
    #that values came from another file
    template_env.all.each do |_var, value|
      unless value.original_line
        #TODO: This has been broken for a while now and no one noticed
        #so maybe we can skip it
        value.original_line = value.line
      end
    end

    #Run source through AliasProcessor with instance variables from the
    #current environment.
    #TODO: Add in :locals => { ... } to environment
    src = Brakeman::TemplateAliasProcessor.new(@tracker, template, called_from).process_safely(template.src, template_env)

    digest = Digest::SHA1.new.update(name + src.to_s).to_s.to_sym

    if @tracker.template_cache.include? digest
      return
    else
      @tracker.template_cache << digest
    end

    #Run alias-processed src through the template processor to pull out
    #information and outputs.
    #This information will be stored in tracker.templates, but with a name
    #specifying this particular route. The original source should remain
    #pristine (so it can be processed within other environments).
    @tracker.processor.process_template name, src, template.type, called_from, template.file
  end
end

#template_name(name) ⇒ Object

Override to process name, such as adding the controller name.


158
159
160
# File 'lib/brakeman/processors/lib/render_helper.rb', line 158

def template_name name
  raise "RenderHelper#template_name should be overridden."
end