FIX: Apply censored words to inline onebox (#16873)

Censored watched words were not censored inside the title of an inline
oneboxes. Malicious users could exploit this behaviour to insert bad
words. The same issue has been fixed for regular Oneboxes in commit
d184fe59ca.
This commit is contained in:
Bianca Nenciu 2022-05-25 14:51:47 +03:00 committed by GitHub
parent 6268fe7495
commit 7328a2bfb0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 41 additions and 11 deletions

View File

@ -103,21 +103,18 @@ class WordWatcher
doc = Nokogiri::HTML5::fragment(html)
doc.traverse do |node|
if node.text?
node.content = node.content.gsub(regexp) do |match|
# the regex captures leading whitespaces
padding = match.size - match.lstrip.size
if padding > 0
match[0..padding - 1] + REPLACEMENT_LETTER * (match.size - padding)
else
REPLACEMENT_LETTER * match.size
end
end
end
node.content = censor_text_with_regexp(node.content, regexp) if node.text?
end
doc.to_s
end
def self.censor_text(text)
regexp = WordWatcher.word_matcher_regexp(:censor)
return text if regexp.blank?
censor_text_with_regexp(text, regexp)
end
def self.clear_cache!
WatchedWord.actions.each do |a, i|
Discourse.cache.delete word_matcher_regexp_key(a)
@ -172,4 +169,18 @@ class WordWatcher
def word_matches?(word)
Regexp.new(WordWatcher.word_to_regexp(word, whole: true), Regexp::IGNORECASE).match?(@raw)
end
private
def self.censor_text_with_regexp(text, regexp)
text.gsub(regexp) do |match|
# the regex captures leading whitespaces
padding = match.size - match.lstrip.size
if padding > 0
match[0..padding - 1] + REPLACEMENT_LETTER * (match.size - padding)
else
REPLACEMENT_LETTER * match.size
end
end
end
end

View File

@ -108,6 +108,7 @@ class InlineOneboxer
end
end
onebox = { url: url, title: title && Emoji.gsub_emoji_to_unicode(title) }
onebox[:title] = WordWatcher.censor_text(onebox[:title])
Discourse.cache.write(cache_key(url), onebox, expires_in: 1.day) if !opts[:skip_cache]
onebox
end

View File

@ -313,6 +313,24 @@ describe InlineOneboxer do
expect(onebox[:title]).to be_blank
end
end
it "censors external oneboxes" do
Fabricate(:watched_word, action: WatchedWord.actions[:censor], word: "my")
SiteSetting.enable_inline_onebox_on_all_domains = true
stub_request(:get, "https://eviltrout.com/some-path").
to_return(status: 200, body: "<html><head><title>welcome to my blog</title></head></html>")
onebox = InlineOneboxer.lookup(
"https://eviltrout.com/some-path",
skip_cache: true
)
expect(onebox).to be_present
expect(onebox[:url]).to eq("https://eviltrout.com/some-path")
expect(onebox[:title]).to eq("welcome to ■■ blog")
end
end
context "register_local_handler" do