diff --git a/src/common/utils/util.test.js b/src/common/utils/util.test.js index f59f584f..e641d20d 100644 --- a/src/common/utils/util.test.js +++ b/src/common/utils/util.test.js @@ -1,7 +1,7 @@ // Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import Utils from 'common/utils/util'; +import Utils, {escapeRegex} from 'common/utils/util'; describe('common/utils/util', () => { describe('shorten', () => { @@ -115,4 +115,12 @@ describe('common/utils/util', () => { expect(Utils.boundsDiff(base, actual)).toEqual(diff); }); }); + + describe('escapeRegex', () => { + it('should escape special chars in string when used inside regex', () => { + const str = 'Language C++'; + const regex = `${escapeRegex(str)}___TAB_[A-Z]+`; + expect(new RegExp(regex).test('Language C++___TAB_ABCDEF')).toBe(true); + }); + }); }); diff --git a/src/common/utils/util.ts b/src/common/utils/util.ts index 37a1a088..39287bad 100644 --- a/src/common/utils/util.ts +++ b/src/common/utils/util.ts @@ -58,9 +58,18 @@ function boundsDiff(base: Rectangle, actual: Rectangle) { }; } +// MM-48463 - https://stackoverflow.com/a/3561711/5605822 +export const escapeRegex = (s?: string) => { + if (typeof s !== 'string') { + return ''; + } + return s.replace(/[/\-\\^$*+?.()|[\]{}]/g, '\\$&'); +}; + export default { runMode, shorten, isVersionGreaterThanOrEqualTo, boundsDiff, + escapeRegex, }; diff --git a/src/renderer/components/MainPage.tsx b/src/renderer/components/MainPage.tsx index 475c2b99..b7ba76e4 100644 --- a/src/renderer/components/MainPage.tsx +++ b/src/renderer/components/MainPage.tsx @@ -14,6 +14,7 @@ import {TeamWithTabs} from 'types/config'; import {DownloadedItems} from 'types/downloads'; import {getTabViewName} from 'common/tabs/TabView'; +import {escapeRegex} from 'common/utils/util'; import restoreButton from '../../assets/titlebar/chrome-restore.svg'; import maximizeButton from '../../assets/titlebar/chrome-maximize.svg'; @@ -462,7 +463,7 @@ class MainPage extends React.PureComponent { ); } - const serverMatch = `${this.state.activeServerName}___TAB_[A-Z]+`; + const serverMatch = `${escapeRegex(this.state.activeServerName)}___TAB_[A-Z]+`; const totalMentionCount = Object.keys(this.state.mentionCounts).reduce((sum, key) => { // Strip out current server from unread and mention counts if (this.state.activeServerName && key.match(serverMatch)) {