Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HTML escape YAML after parsing to prevent invalidating YAML string #454

Merged
merged 1 commit into from
May 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 20 additions & 1 deletion lib/gollum-lib/filter/yaml.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ def extract(data)
data.gsub!(YAML_FRONT_MATTER_REGEXP) do
@markup.metadata ||= {}
begin
frontmatter = ::YAML.safe_load(sanitize(Regexp.last_match[1]))
frontmatter = sanitize_frontmatter(::YAML.safe_load(Regexp.last_match[1]))
@markup.metadata.merge!(frontmatter) if frontmatter.respond_to?(:keys) && frontmatter.respond_to?(:values)
rescue ::Psych::SyntaxError, ::Psych::DisallowedClass, ::Psych::BadAlias => error
@markup.metadata['errors'] ||= []
Expand All @@ -24,4 +24,23 @@ def extract(data)
def process(data)
data
end

private

def sanitize_frontmatter(obj)
case obj
when Hash
obj.map do |k, v|
[sanitize(k.to_s), sanitize_frontmatter(v)]
end.to_h
when Array
obj.map! do |v|
sanitize_frontmatter(v)
end
when String
sanitize(obj)
else
obj
end
end
end
75 changes: 75 additions & 0 deletions test/filter/test_yaml.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
path = File.join(File.dirname(__FILE__), "..", "helper")
require File.expand_path(path)

context "Gollum::Filter::YAML" do
setup do
@page = mock_page
@markup = Gollum::Markup.new(@page)
@filter = Gollum::Filter::YAML.new(@markup)
end

def filter(content)
@filter.process(@filter.extract(content))
end

test 'process yaml' do
markup = <<~EOF
---
Literal Scalar: |
abc

123
Folded Scalar: >
abc

123
Escaped: "abc\n\n123"
---

# Markdown content here
EOF

result = {"Escaped"=> "abc\n" + "123",
"Folded Scalar" => "abc\n" + "123\n",
"Literal Scalar" => "abc\n" + "\n" + "123\n"
}

assert_equal "# Markdown content here\n", filter(markup)
assert_nil @markup.metadata['errors']
assert_equal result, @markup.metadata
end

test 'escape yaml' do
markup = <<~EOF
---
BadStuffInKey<script>bad()</script>: foo
Literal Scalar: |
<script>foo</script>

123
Folded Scalar: >
>abc

<123
Escaped: "abc<script>123</script>"
NestedBadStuff:
Baz:
- [1, "<script>bad()</script>"]
- [1, 2, 3]
---

# Markdown content here
EOF

result = {"Escaped"=> "abc",
"Folded Scalar" => "&gt;abc\n" + "&lt;123\n",
"Literal Scalar" => "\n" + "\n" + "123\n",
"BadStuffInKey" => "foo",
"NestedBadStuff"=> {"Baz"=>[[1, ""], [1, 2, 3]]}
}
filter(markup)
assert_nil @markup.metadata['errors']
assert_equal result, @markup.metadata
end

end
4 changes: 4 additions & 0 deletions test/helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,10 @@ def metadata(val={})
val
end

def sanitizer
Gollum::Sanitization.new(Gollum::Markup.to_xml_opts)
end

attr_reader :repo_is_bare
attr_reader :base_path
end
Expand Down
Loading