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


168
169
170
171
172
173
174
175
176
177
178
179
# File 'lib/brakeman/processors/lib/render_helper.rb', line 168

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


155
156
157
158
159
160
161
162
163
164
165
166
# File 'lib/brakeman/processors/lib/render_helper.rb', line 155

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) ⇒ 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
  if name.is_a? String or name.is_a? Symbol
    process_template template_name(name), args
  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
end

#process_partial(name, args) ⇒ 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
  if name == "" or !(string? name or symbol? name)
    return
  end

  names = name.value.to_s.split("/")
  names[-1] = "_" + names[-1]
  process_template template_name(names.join("/")), args
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
    process_action exp[2][1], exp[3]
  when :default
    begin
      process_template template_name, exp[3]
    rescue ArgumentError
      Brakeman.debug "Problem processing render: #{exp}"
    end
  when :partial, :layout
    process_partial exp[2], exp[3]
  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
# 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

  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
    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|
        template_env[Sexp.new(:call, nil, key.value)] = value
      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
  end
end

#template_name(name) ⇒ Object

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


150
151
152
# File 'lib/brakeman/processors/lib/render_helper.rb', line 150

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