Commit 47188b3b authored by Oswaldo Ferreira's avatar Oswaldo Ferreira

Ensure HTML safety of new HSET/HMGET diffs cache

It extracts a method to be reused by all diff caches,
which ensures the rich_text of diff lines are
html safe. Otherwise we'd see a wrong state in
the diff changes tab.
parent fba0d03c
...@@ -21,7 +21,7 @@ module Gitlab ...@@ -21,7 +21,7 @@ module Gitlab
def decorate(diff_file) def decorate(diff_file)
if content = read_file(diff_file) if content = read_file(diff_file)
diff_file.highlighted_diff_lines = content.map do |line| diff_file.highlighted_diff_lines = content.map do |line|
Gitlab::Diff::Line.init_from_hash(line) Gitlab::Diff::Line.safe_init_from_hash(line)
end end
end end
end end
......
...@@ -34,6 +34,14 @@ module Gitlab ...@@ -34,6 +34,14 @@ module Gitlab
rich_text: hash[:rich_text]) rich_text: hash[:rich_text])
end end
def self.safe_init_from_hash(hash)
line = hash.with_indifferent_access
rich_text = line[:rich_text]
line[:rich_text] = rich_text&.html_safe
init_from_hash(line)
end
def to_hash def to_hash
hash = {} hash = {}
SERIALIZE_KEYS.each { |key| hash[key] = send(key) } # rubocop:disable GitlabSecurity/PublicSend SERIALIZE_KEYS.each { |key| hash[key] = send(key) } # rubocop:disable GitlabSecurity/PublicSend
......
...@@ -43,11 +43,7 @@ module Gitlab ...@@ -43,11 +43,7 @@ module Gitlab
next unless lines next unless lines
JSON.parse(lines).map! do |line| JSON.parse(lines).map! do |line|
line = line.with_indifferent_access Gitlab::Diff::Line.safe_init_from_hash(line)
rich_text = line[:rich_text]
line[:rich_text] = rich_text&.html_safe
Gitlab::Diff::Line.init_from_hash(line)
end end
end end
end end
......
...@@ -68,6 +68,15 @@ describe Gitlab::Diff::HighlightCache, :clean_gitlab_redis_cache do ...@@ -68,6 +68,15 @@ describe Gitlab::Diff::HighlightCache, :clean_gitlab_redis_cache do
expect(diff_file.highlighted_diff_lines.size).to be > 5 expect(diff_file.highlighted_diff_lines.size).to be > 5
end end
it 'assigns highlighted diff lines which rich_text are HTML-safe' do
cache.write_if_empty
cache.decorate(diff_file)
rich_texts = diff_file.highlighted_diff_lines.map(&:rich_text)
expect(rich_texts).to all(be_html_safe)
end
end end
describe '#write_if_empty' do describe '#write_if_empty' do
......
# frozen_string_literal: true # frozen_string_literal: true
require 'spec_helper'
describe Gitlab::Diff::Line do describe Gitlab::Diff::Line do
describe '.init_from_hash' do shared_examples 'line object initialized by hash' do
it 'round-trips correctly with to_hash' do it 'round-trips correctly with to_hash' do
line = described_class.new('<input>', 'match', 0, 0, 1, expect(described_class.safe_init_from_hash(line.to_hash).to_hash)
parent_file: double(:file),
line_code: double(:line_code),
rich_text: '&lt;input&gt;')
expect(described_class.init_from_hash(line.to_hash).to_hash)
.to eq(line.to_hash) .to eq(line.to_hash)
end end
end end
let(:line) do
described_class.new('<input>', 'match', 0, 0, 1,
parent_file: double(:file),
line_code: double(:line_code),
rich_text: rich_text)
end
describe '.init_from_hash' do
let(:rich_text) { '&lt;input&gt;' }
it_behaves_like 'line object initialized by hash'
end
describe '.safe_init_from_hash' do
let(:rich_text) { '<input>' }
it_behaves_like 'line object initialized by hash'
it 'ensures rich_text is HTML-safe' do
expect(line.rich_text).not_to be_html_safe
new_line = described_class.safe_init_from_hash(line.to_hash)
expect(new_line.rich_text).to be_html_safe
end
context 'when given hash has no rich_text' do
it_behaves_like 'line object initialized by hash' do
let(:rich_text) { nil }
end
end
end
context "when setting rich text" do context "when setting rich text" do
it 'escapes any HTML special characters in the diff chunk header' do it 'escapes any HTML special characters in the diff chunk header' do
subject = described_class.new("<input>", "", 0, 0, 0) subject = described_class.new("<input>", "", 0, 0, 0)
......
...@@ -62,6 +62,15 @@ describe Gitlab::DiscussionsDiff::HighlightCache, :clean_gitlab_redis_cache do ...@@ -62,6 +62,15 @@ describe Gitlab::DiscussionsDiff::HighlightCache, :clean_gitlab_redis_cache do
expect(found.second.size).to eq(2) expect(found.second.size).to eq(2)
expect(found.second).to all(be_a(Gitlab::Diff::Line)) expect(found.second).to all(be_a(Gitlab::Diff::Line))
end end
it 'returns lines which rich_text are HTML-safe' do
described_class.write_multiple(mapping)
found = described_class.read_multiple(mapping.keys)
rich_texts = found.flatten.map(&:rich_text)
expect(rich_texts).to all(be_html_safe)
end
end end
describe '#clear_multiple' do describe '#clear_multiple' do
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment