From c7820d8124c854760a4d288334f185de2fb99446 Mon Sep 17 00:00:00 2001 From: John Hawthorn Date: Mon, 18 Mar 2019 17:17:11 -0700 Subject: Introduce Template::File as new render file: The previous behaviour of render file: was essentially the same as render template:, except that templates can be specified as an absolute path on the filesystem. This makes sense for historic reasons, but now render file: is almost exclusively used to render raw files (not .erb) like public/404.html. In addition to complicating the code in template/resolver.rb, I think the current behaviour is surprising to developers. This commit deprecates the existing "lookup a template from anywhere" behaviour and replaces it with "render this file exactly as it is on disk". Handlers will no longer be used (it will render the same as if the :raw handler was used), but formats (.html, .xml, etc) will still be detected (and will default to :plain). The existing render file: behaviour was the path through which Rails apps were vulnerable in the recent CVE-2019-5418. Although the vulnerability has been patched in a fully backwards-compatible way, I think it's a strong hint that we should drop the existing previously-vulnerable behaviour if it isn't a benefit to developers. --- actionview/lib/action_view/file_template.rb | 2 +- .../lib/action_view/renderer/template_renderer.rb | 7 +++++- actionview/lib/action_view/template.rb | 3 ++- actionview/lib/action_view/template/error.rb | 2 +- actionview/lib/action_view/template/file.rb | 28 ++++++++++++++++++++++ 5 files changed, 38 insertions(+), 4 deletions(-) create mode 100644 actionview/lib/action_view/template/file.rb (limited to 'actionview/lib/action_view') diff --git a/actionview/lib/action_view/file_template.rb b/actionview/lib/action_view/file_template.rb index dea02176eb..e0dc7da3b6 100644 --- a/actionview/lib/action_view/file_template.rb +++ b/actionview/lib/action_view/file_template.rb @@ -11,7 +11,7 @@ module ActionView end def source - File.binread @filename + ::File.binread @filename end def refresh(_) diff --git a/actionview/lib/action_view/renderer/template_renderer.rb b/actionview/lib/action_view/renderer/template_renderer.rb index 9548fe12c4..60cb2ceafa 100644 --- a/actionview/lib/action_view/renderer/template_renderer.rb +++ b/actionview/lib/action_view/renderer/template_renderer.rb @@ -26,7 +26,12 @@ module ActionView elsif options.key?(:html) Template::HTML.new(options[:html], formats.first) elsif options.key?(:file) - @lookup_context.with_fallbacks.find_file(options[:file], nil, false, keys, @details) + if File.exist?(options[:file]) + Template::File.new(options[:file]) + else + ActiveSupport::Deprecation.warn "render file: should be given the absolute path to a file" + @lookup_context.with_fallbacks.find_file(options[:file], nil, false, keys, @details) + end elsif options.key?(:inline) handler = Template.handler_for_extension(options[:type] || "erb") format = if handler.respond_to?(:default_format) diff --git a/actionview/lib/action_view/template.rb b/actionview/lib/action_view/template.rb index 6e3af1536a..2230de2ca2 100644 --- a/actionview/lib/action_view/template.rb +++ b/actionview/lib/action_view/template.rb @@ -113,6 +113,7 @@ module ActionView eager_autoload do autoload :Error + autoload :File autoload :Handlers autoload :HTML autoload :Inline @@ -139,7 +140,7 @@ module ActionView @virtual_path = virtual_path @variable = if @virtual_path - base = @virtual_path[-1] == "/" ? "" : File.basename(@virtual_path) + base = @virtual_path[-1] == "/" ? "" : ::File.basename(@virtual_path) base =~ /\A_?(.*?)(?:\.\w+)*\z/ $1.to_sym end diff --git a/actionview/lib/action_view/template/error.rb b/actionview/lib/action_view/template/error.rb index 4e3c02e05e..e6d9e35815 100644 --- a/actionview/lib/action_view/template/error.rb +++ b/actionview/lib/action_view/template/error.rb @@ -104,7 +104,7 @@ module ActionView def line_number @line_number ||= if file_name - regexp = /#{Regexp.escape File.basename(file_name)}:(\d+)/ + regexp = /#{Regexp.escape ::File.basename(file_name)}:(\d+)/ $1 if message =~ regexp || backtrace.find { |line| line =~ regexp } end end diff --git a/actionview/lib/action_view/template/file.rb b/actionview/lib/action_view/template/file.rb new file mode 100644 index 0000000000..487e5735cf --- /dev/null +++ b/actionview/lib/action_view/template/file.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +module ActionView #:nodoc: + # = Action View File Template + class Template #:nodoc: + class File #:nodoc: + attr_accessor :type, :format + + def initialize(filename) + @filename = filename.to_s + extname = ::File.extname(filename).delete(".") + @type = Template::Types[extname] || Template::Types[:text] + @format = @type.symbol + end + + def identifier + @filename + end + + def render(*args) + ::File.read(@filename) + end + + def formats; Array(format); end + deprecate :formats + end + end +end -- cgit v1.2.3