diff --git a/app/services/word_watcher.rb b/app/services/word_watcher.rb index 28f38b9a97e..bc056fd6b46 100644 --- a/app/services/word_watcher.rb +++ b/app/services/word_watcher.rb @@ -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 diff --git a/lib/inline_oneboxer.rb b/lib/inline_oneboxer.rb index 22bf4762378..7b4d78fc7ab 100644 --- a/lib/inline_oneboxer.rb +++ b/lib/inline_oneboxer.rb @@ -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 diff --git a/spec/lib/inline_oneboxer_spec.rb b/spec/lib/inline_oneboxer_spec.rb index 10dcb4b607b..0590d5b1303 100644 --- a/spec/lib/inline_oneboxer_spec.rb +++ b/spec/lib/inline_oneboxer_spec.rb @@ -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: "welcome to my blog") + + 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