Commit 06be63d0 authored by Nick Thomas's avatar Nick Thomas

Merge branch 'osw-ensures-html-safety-of-new-diff-cache' into 'master'

Ensure HTML safety of new HSET/HMGET diffs cache

Closes #39104

See merge request gitlab-org/gitlab!21521
parents 9ce1c711 47188b3b
...@@ -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