1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00
rails--rails/actionview/test/template/lookup_context_test.rb
John Hawthorn eb52904eb5 Always reject files external to app
Previously, when using `render file:`, it was possible to render files
not only at an absolute path or relative to the current directory, but
relative to ANY view paths. This was probably done for absolutely
maximum compatibility when addressing CVE-2016-0752, but I think is
unlikely to be used in practice.

Tihs commit removes the ability to `render file:` with a path relative
to a non-fallback view path.

Make FallbackResolver.new private

To ensure nobody is making FallbackResolvers other than "/" and "".

Make reject_files_external_... no-op for fallbacks

Because there are only two values used for path: "" and "/", and
File.join("", "") == File.join("/", "") == "/", this method was only
testing that the absolute paths started at "/" (which of course all do).

This commit doesn't change any behaviour, but it makes it explicit that
the FallbackFileSystemResolver works this way.

Remove outside_app_allowed argument

Deprecate find_all_anywhere

This is now equivalent to find_all

Remove outside_app argument

Deprecate find_file for find

Both LookupContext#find_file and PathSet#find_file are now equivalent to
their respective #find methods.
2019-04-03 09:02:28 -07:00

272 lines
9.2 KiB
Ruby

# frozen_string_literal: true
require "abstract_unit"
require "abstract_controller/rendering"
class LookupContextTest < ActiveSupport::TestCase
def setup
@lookup_context = build_lookup_context(FIXTURE_LOAD_PATH, {})
ActionView::LookupContext::DetailsKey.clear
end
def build_lookup_context(paths, details)
ActionView::LookupContext.new(paths, details)
end
def teardown
I18n.locale = :en
end
test "rendered_format is deprecated" do
assert_deprecated do
@lookup_context.rendered_format = "foo"
end
assert_deprecated do
assert_equal "foo", @lookup_context.rendered_format
end
end
test "allows to override default_formats with ActionView::Base.default_formats" do
formats = ActionView::Base.default_formats
ActionView::Base.default_formats = [:foo, :bar]
assert_equal [:foo, :bar], ActionView::LookupContext.new([]).default_formats
ensure
ActionView::Base.default_formats = formats
end
test "process view paths on initialization" do
assert_kind_of ActionView::PathSet, @lookup_context.view_paths
end
test "normalizes details on initialization" do
assert_equal Mime::SET.to_a, @lookup_context.formats
assert_equal :en, @lookup_context.locale
end
test "allows me to freeze and retrieve frozen formats" do
@lookup_context.formats.freeze
assert_predicate @lookup_context.formats, :frozen?
end
test "provides getters and setters for variants" do
@lookup_context.variants = [:mobile]
assert_equal [:mobile], @lookup_context.variants
end
test "provides getters and setters for formats" do
@lookup_context.formats = [:html]
assert_equal [:html], @lookup_context.formats
end
test "handles */* formats" do
@lookup_context.formats = ["*/*"]
assert_equal Mime::SET.to_a, @lookup_context.formats
end
test "handles explicitly defined */* formats fallback to :js" do
@lookup_context.formats = [:js, Mime::ALL]
assert_equal [:js, *Mime::SET.symbols].uniq, @lookup_context.formats
end
test "adds :html fallback to :js formats" do
@lookup_context.formats = [:js]
assert_equal [:js, :html], @lookup_context.formats
end
test "raises on invalid format assignment" do
ex = assert_raises ArgumentError do
@lookup_context.formats = [:html, :invalid, "also bad"]
end
assert_equal 'Invalid formats: :invalid, "also bad"', ex.message
end
test "provides getters and setters for locale" do
@lookup_context.locale = :pt
assert_equal :pt, @lookup_context.locale
end
test "changing lookup_context locale, changes I18n.locale" do
@lookup_context.locale = :pt
assert_equal :pt, I18n.locale
end
test "delegates changing the locale to the I18n configuration object if it contains a lookup_context object" do
begin
I18n.config = ActionView::I18nProxy.new(I18n.config, @lookup_context)
@lookup_context.locale = :pt
assert_equal :pt, I18n.locale
assert_equal :pt, @lookup_context.locale
ensure
I18n.config = I18n.config.original_config
end
assert_equal :pt, I18n.locale
end
test "find templates using the given view paths and configured details" do
template = @lookup_context.find("hello_world", %w(test))
assert_equal "Hello world!", template.source
@lookup_context.locale = :da
template = @lookup_context.find("hello_world", %w(test))
assert_equal "Hey verden", template.source
end
test "find templates with given variants" do
@lookup_context.formats = [:html]
@lookup_context.variants = [:phone]
template = @lookup_context.find("hello_world", %w(test))
assert_equal "Hello phone!", template.source
@lookup_context.variants = [:phone]
@lookup_context.formats = [:text]
template = @lookup_context.find("hello_world", %w(test))
assert_equal "Hello texty phone!", template.source
end
test "found templates have nil format if one cannot be found from template or handler" do
assert_called(ActionView::Template::Handlers::Builder, :default_format, returns: nil) do
@lookup_context.formats = [:text]
template = @lookup_context.find("hello", %w(test))
assert_nil template.format
end
end
test "adds fallbacks to view paths when required" do
assert_equal 1, @lookup_context.view_paths.size
assert_deprecated do
@lookup_context.with_fallbacks do
assert_equal 3, @lookup_context.view_paths.size
assert_includes @lookup_context.view_paths, ActionView::FallbackFileSystemResolver.instances[0]
assert_includes @lookup_context.view_paths, ActionView::FallbackFileSystemResolver.instances[1]
end
end
@lookup_context = @lookup_context.with_fallbacks
assert_equal 3, @lookup_context.view_paths.size
assert_includes @lookup_context.view_paths, ActionView::FallbackFileSystemResolver.instances[0]
assert_includes @lookup_context.view_paths, ActionView::FallbackFileSystemResolver.instances[1]
end
test "add fallbacks just once in nested fallbacks calls" do
assert_deprecated do
@lookup_context.with_fallbacks do
@lookup_context.with_fallbacks do
assert_equal 3, @lookup_context.view_paths.size
end
end
end
@lookup_context = @lookup_context.with_fallbacks.with_fallbacks
assert_equal 3, @lookup_context.view_paths.size
end
test "generates a new details key for each details hash" do
keys = []
keys << @lookup_context.details_key
assert_equal 1, keys.uniq.size
@lookup_context.locale = :da
keys << @lookup_context.details_key
assert_equal 2, keys.uniq.size
@lookup_context.locale = :en
keys << @lookup_context.details_key
assert_equal 2, keys.uniq.size
@lookup_context.formats = [:html]
keys << @lookup_context.details_key
assert_equal 3, keys.uniq.size
@lookup_context.formats = nil
keys << @lookup_context.details_key
assert_equal 3, keys.uniq.size
end
test "gives the key forward to the resolver, so it can be used as cache key" do
@lookup_context = build_lookup_context(ActionView::FixtureResolver.new("test/_foo.erb" => "Foo"), {})
template = @lookup_context.find("foo", %w(test), true)
assert_equal "Foo", template.source
# Now we are going to change the template, but it won't change the returned template
# since we will hit the cache.
@lookup_context.view_paths.first.data["test/_foo.erb"] = "Bar"
template = @lookup_context.find("foo", %w(test), true)
assert_equal "Foo", template.source
# This time we will change the locale. The updated template should be picked since
# lookup_context generated a new key after we changed the locale.
@lookup_context.locale = :da
template = @lookup_context.find("foo", %w(test), true)
assert_equal "Bar", template.source
# Now we will change back the locale and it will still pick the old template.
# This is expected because lookup_context will reuse the previous key for :en locale.
@lookup_context.locale = :en
template = @lookup_context.find("foo", %w(test), true)
assert_equal "Foo", template.source
# Finally, we can expire the cache. And the expected template will be used.
@lookup_context.view_paths.first.clear_cache
template = @lookup_context.find("foo", %w(test), true)
assert_equal "Bar", template.source
end
test "can disable the cache on demand" do
@lookup_context = build_lookup_context(ActionView::FixtureResolver.new("test/_foo.erb" => "Foo"), {})
old_template = @lookup_context.find("foo", %w(test), true)
template = @lookup_context.find("foo", %w(test), true)
assert_equal template, old_template
assert @lookup_context.cache
template = @lookup_context.disable_cache do
assert_not @lookup_context.cache
@lookup_context.find("foo", %w(test), true)
end
assert @lookup_context.cache
assert_not_equal template, old_template
end
test "responds to #prefixes" do
assert_equal [], @lookup_context.prefixes
@lookup_context.prefixes = ["foo"]
assert_equal ["foo"], @lookup_context.prefixes
end
end
class TestMissingTemplate < ActiveSupport::TestCase
def setup
@lookup_context = ActionView::LookupContext.new("/Path/to/views", {})
end
test "if no template was found we get a helpful error message including the inheritance chain" do
e = assert_raise ActionView::MissingTemplate do
@lookup_context.find("foo", %w(parent child))
end
assert_match %r{Missing template parent/foo, child/foo with .* Searched in:\n \* "/Path/to/views"\n}, e.message
end
test "if no partial was found we get a helpful error message including the inheritance chain" do
e = assert_raise ActionView::MissingTemplate do
@lookup_context.find("foo", %w(parent child), true)
end
assert_match %r{Missing partial parent/_foo, child/_foo with .* Searched in:\n \* "/Path/to/views"\n}, e.message
end
test "if a single prefix is passed as a string and the lookup fails, MissingTemplate accepts it" do
e = assert_raise ActionView::MissingTemplate do
details = { handlers: [], formats: [], variants: [], locale: [] }
@lookup_context.view_paths.find("foo", "parent", true, details)
end
assert_match %r{Missing partial parent/_foo with .* Searched in:\n \* "/Path/to/views"\n}, e.message
end
end