lib/brakeman/parsers/template_parser.rb
module Brakeman
class TemplateParser
include Brakeman::Util
attr_reader :tracker
KNOWN_TEMPLATE_EXTENSIONS = /.*\.(erb|haml|rhtml|slim)$/
TemplateFile = Struct.new(:path, :ast, :name, :type)
def initialize tracker, file_parser
@tracker = tracker
@file_parser = file_parser
@slim_smart = nil # Load slim/smart ?
end
def parse_template path, text
type = path.relative.match(KNOWN_TEMPLATE_EXTENSIONS)[1].to_sym
type = :erb if type == :rhtml
name = template_path_to_name path
Brakeman.debug "Parsing #{path}"
begin
src = case type
when :erb
type = :erubis if erubis?
parse_erb path, text
when :haml
parse_haml path, text
when :slim
parse_slim path, text
else
tracker.error "Unknown template type in #{path}"
nil
end
if src and ast = @file_parser.parse_ruby(src, path)
@file_parser.file_list << TemplateFile.new(path, ast, name, type)
end
rescue Racc::ParseError => e
tracker.error e, "Could not parse #{path}"
rescue StandardError, LoadError => e
tracker.error e.exception(e.message + "\nWhile processing #{path}"), e.backtrace
end
nil
end
def parse_erb path, text
if tracker.config.escape_html?
if tracker.options[:rails3]
require 'brakeman/parsers/rails3_erubis'
Brakeman::Rails3Erubis.new(text, :filename => path).src
else
require 'brakeman/parsers/rails2_xss_plugin_erubis'
Brakeman::Rails2XSSPluginErubis.new(text, :filename => path).src
end
elsif tracker.config.erubis?
require 'brakeman/parsers/rails2_erubis'
Brakeman::ScannerErubis.new(text, :filename => path).src
else
require 'erb'
src = if ERB.instance_method(:initialize).parameters.assoc(:key) # Ruby 2.6+
ERB.new(text, trim_mode: '-').src
else
ERB.new(text, nil, '-').src
end
src.sub!(/^#.*\n/, '')
src
end
end
def erubis?
tracker.config.escape_html? or
tracker.config.erubis?
end
def parse_haml path, text
Brakeman.load_brakeman_dependency 'haml'
require_relative 'haml_embedded'
Haml::Engine.new(text,
:filename => path,
:escape_html => tracker.config.escape_html?,
:escape_filter_interpolations => tracker.config.escape_filter_interpolations?
).precompiled.gsub(/([^\\])\\n/, '\1')
rescue Haml::Error => e
tracker.error e, ["While compiling HAML in #{path}"] << e.backtrace
nil
end
def parse_slim path, text
Brakeman.load_brakeman_dependency 'slim'
if @slim_smart.nil? and load_slim_smart?
@slim_smart = true
Brakeman.load_brakeman_dependency 'slim/smart'
else
@slim_smart = false
end
require_relative 'slim_embedded'
Slim::Template.new(path,
:disable_capture => true,
:generator => Temple::Generators::RailsOutputBuffer) { text }.precompiled_template
end
def load_slim_smart?
return !@slim_smart unless @slim_smart.nil?
# Terrible hack to find
# gem "slim", "~> 3.0.1", require: ["slim", "slim/smart"]
if tracker.app_tree.exists? 'Gemfile'
gemfile_contents = tracker.app_tree.file_path('Gemfile').read
if gemfile_contents.include? 'slim/smart'
return true
end
end
false
end
def self.parse_inline_erb tracker, text
fp = Brakeman::FileParser.new(tracker.app_tree, tracker.options[:parser_timeout])
tp = self.new(tracker, fp)
src = tp.parse_erb '_inline_', text
type = tp.erubis? ? :erubis : :erb
return type, fp.parse_ruby(src, "_inline_")
end
end
end