lib/roda/plugins/render.rb in roda-2.12.0 vs lib/roda/plugins/render.rb in roda-2.13.0
- old
+ new
@@ -26,14 +26,18 @@
#
# = Plugin Options
#
# The following plugin options are supported:
#
+ # :allowed_paths :: Set the template paths to allow if +:check_paths+ is true.
+ # Defaults to the +:views+ directory.
# :cache :: nil/false to not cache templates (useful for development), defaults
# to true unless RACK_ENV is development to automatically use the
# default template cache.
# :cache_class :: A class to use as the template cache instead of the default.
+ # :check_paths :: Check template paths start with one of the entries in +:allowed_paths+,
+ # and raise a RodaError if the path doesn't.
# :engine :: The tilt engine to use for rendering, also the default file extension for
# templates, defaults to 'erb'.
# :escape :: Use Roda's Erubis escaping support, which makes <tt><%= %></tt> escape output,
# <tt><%== %></tt> not escape output, and handles postfix conditions inside
# <tt><%= %></tt> tags.
@@ -135,10 +139,12 @@
app.opts[:render][:orig_opts] = opts
opts = app.opts[:render]
opts[:engine] = (opts[:engine] || opts[:ext] || "erb").dup.freeze
opts[:views] = File.expand_path(opts[:views]||"views", app.opts[:root]).freeze
+ opts[:allowed_paths] ||= [opts[:views]].freeze
+ opts[:allowed_paths] = opts[:allowed_paths].map{|f| ::File.expand_path(f)}.uniq.freeze
if opts.fetch(:cache, ENV['RACK_ENV'] != 'development')
if cache_class = opts[:cache_class]
opts[:cache] = cache_class.new
else
@@ -350,10 +356,17 @@
opts[:template].to_s
end
# The template path for the given options.
def template_path(opts)
- "#{opts[:views]}/#{template_name(opts)}.#{opts[:engine]}"
+ path = "#{opts[:views]}/#{template_name(opts)}.#{opts[:engine]}"
+ if opts.fetch(:check_paths){render_opts[:check_paths]}
+ full_path = ::File.expand_path(path)
+ unless render_opts[:allowed_paths].any?{|f| full_path.start_with?(f)}
+ raise RodaError, "attempt to render path not in allowed_paths: #{path} (allowed: #{render_opts[:allowed_paths].join(', ')})"
+ end
+ end
+ path
end
# If a layout should be used, return a hash of options for
# rendering the layout template. If a layout should not be
# used, return nil.