mirror of
https://github.com/discourse/discourse.git
synced 2025-06-04 04:14:38 +08:00
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 d184fe59ca7885741ed9f840d3209a9a5ed861ea.
This commit is contained in:
@ -103,21 +103,18 @@ class WordWatcher
|
|||||||
|
|
||||||
doc = Nokogiri::HTML5::fragment(html)
|
doc = Nokogiri::HTML5::fragment(html)
|
||||||
doc.traverse do |node|
|
doc.traverse do |node|
|
||||||
if node.text?
|
node.content = censor_text_with_regexp(node.content, regexp) 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
|
|
||||||
end
|
end
|
||||||
doc.to_s
|
doc.to_s
|
||||||
end
|
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!
|
def self.clear_cache!
|
||||||
WatchedWord.actions.each do |a, i|
|
WatchedWord.actions.each do |a, i|
|
||||||
Discourse.cache.delete word_matcher_regexp_key(a)
|
Discourse.cache.delete word_matcher_regexp_key(a)
|
||||||
@ -172,4 +169,18 @@ class WordWatcher
|
|||||||
def word_matches?(word)
|
def word_matches?(word)
|
||||||
Regexp.new(WordWatcher.word_to_regexp(word, whole: true), Regexp::IGNORECASE).match?(@raw)
|
Regexp.new(WordWatcher.word_to_regexp(word, whole: true), Regexp::IGNORECASE).match?(@raw)
|
||||||
end
|
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
|
end
|
||||||
|
@ -108,6 +108,7 @@ class InlineOneboxer
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
onebox = { url: url, title: title && Emoji.gsub_emoji_to_unicode(title) }
|
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]
|
Discourse.cache.write(cache_key(url), onebox, expires_in: 1.day) if !opts[:skip_cache]
|
||||||
onebox
|
onebox
|
||||||
end
|
end
|
||||||
|
@ -313,6 +313,24 @@ describe InlineOneboxer do
|
|||||||
expect(onebox[:title]).to be_blank
|
expect(onebox[:title]).to be_blank
|
||||||
end
|
end
|
||||||
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
|
end
|
||||||
|
|
||||||
context "register_local_handler" do
|
context "register_local_handler" do
|
||||||
|
Reference in New Issue
Block a user