From 058df4329db685c025a87a9110399a1e9a271929 Mon Sep 17 00:00:00 2001 From: Guo Xiang Tan Date: Tue, 31 Jan 2017 10:39:45 +0800 Subject: [PATCH] FIX: Escape escape regexp characters. --- .../javascripts/pretty-text/censored-words.js.es6 | 8 ++++++-- test/javascripts/lib/pretty-text-test.js.es6 | 10 +++++++++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/app/assets/javascripts/pretty-text/censored-words.js.es6 b/app/assets/javascripts/pretty-text/censored-words.js.es6 index bc9aa59ee0e..9723261833c 100644 --- a/app/assets/javascripts/pretty-text/censored-words.js.es6 +++ b/app/assets/javascripts/pretty-text/censored-words.js.es6 @@ -1,9 +1,13 @@ +function escapeRegexp(text) { + return text.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&') +} + export function censor(text, censoredWords, censoredPattern) { let patterns = [], originalText = text; if (censoredWords && censoredWords.length) { - patterns = censoredWords.split("|").map(t => { return "(" + t.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&') + ")"; }); + patterns = censoredWords.split("|").map(t => `(${escapeRegexp(t)})`); } if (censoredPattern && censoredPattern.length > 0) { @@ -22,7 +26,7 @@ export function censor(text, censoredWords, censoredPattern) { while (m && m[0]) { if (m[0].length > originalText.length) { return originalText; } // regex is dangerous const replacement = new Array(m[0].length+1).join('■'); - text = text.replace(new RegExp("(\\b" + m[0] + "\\b)(?![^\\(]*\\))", "ig"), replacement); + text = text.replace(new RegExp(`(\\b${escapeRegexp(m[0])}\\b)(?![^\\(]*\\))`, "ig"), replacement); m = censorRegexp.exec(text); } } diff --git a/test/javascripts/lib/pretty-text-test.js.es6 b/test/javascripts/lib/pretty-text-test.js.es6 index 790967119a3..5ec6d6deadd 100644 --- a/test/javascripts/lib/pretty-text-test.js.es6 +++ b/test/javascripts/lib/pretty-text-test.js.es6 @@ -11,7 +11,7 @@ const defaultOpts = buildOptions({ emoji_set: 'emoji_one', highlighted_languages: 'json|ruby|javascript', default_code_lang: 'auto', - censored_words: 'shucks|whiz|whizzer', + censored_words: 'shucks|whiz|whizzer|a**le', censored_pattern: '\\d{3}-\\d{4}|tech\\w*' }, getURL: url => url @@ -524,18 +524,26 @@ test("censoring", function() { cooked("aw shucks, golly gee whiz.", "

aw ■■■■■■, golly gee ■■■■.

", "it censors words in the Site Settings"); + cooked("you are a whizzard! I love cheesewhiz. Whiz.", "

you are a whizzard! I love cheesewhiz. ■■■■.

", "it doesn't censor words unless they have boundaries."); + cooked("you are a whizzer! I love cheesewhiz. Whiz.", "

you are a ■■■■■■■! I love cheesewhiz. ■■■■.

", "it censors words even if previous partial matches exist."); + cooked("The link still works. [whiz](http://www.whiz.com)", "

The link still works. ■■■■

", "it won't break links by censoring them."); + cooked("Call techapj the computer whiz at 555-555-1234 for free help.", "

Call ■■■■■■■ the computer ■■■■ at 555-■■■■■■■■ for free help.

", "uses both censored words and patterns from site settings"); + + cooked("I have a pen, I have an a**le", + "

I have a pen, I have an ■■■■■

", + "it escapes regexp chars"); }); test("code blocks/spans hoisting", function() {