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)
.to eq(line.to_hash)
end
end
let(:line) do
described_class.new('<input>', 'match', 0, 0, 1,
parent_file: double(:file), parent_file: double(:file),
line_code: double(:line_code), line_code: double(:line_code),
rich_text: '&lt;input&gt;') rich_text: rich_text)
end
expect(described_class.init_from_hash(line.to_hash).to_hash) describe '.init_from_hash' do
.to eq(line.to_hash) 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
end end
......
...@@ -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