diff --git a/src/common/utils/url.test.js b/src/common/utils/url.test.js index 8b36fbfe..f10ce0d4 100644 --- a/src/common/utils/url.test.js +++ b/src/common/utils/url.test.js @@ -329,4 +329,18 @@ describe('common/utils/url', () => { expect(urlUtils.isCallsPopOutURL()).toBe(false); }); }); + + describe('escapeRegExp', () => { + it('simple', () => { + expect(urlUtils.escapeRegExp('simple')).toBe('simple'); + }); + + it('path', () => { + expect(urlUtils.escapeRegExp('/path/')).toBe('/path/'); + }); + + it('regexp', () => { + expect(urlUtils.escapeRegExp('/path(a+)+')).toBe('/path\\(a\\+\\)\\+'); + }); + }); }); diff --git a/src/common/utils/url.ts b/src/common/utils/url.ts index 72945449..b4d6c32b 100644 --- a/src/common/utils/url.ts +++ b/src/common/utils/url.ts @@ -184,6 +184,12 @@ function cleanPathName(basePathName: string, pathName: string) { return pathName; } +// RegExp string escaping function, as recommended by +// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#escaping +function escapeRegExp(s: string) { + return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string +} + function isCallsPopOutURL(serverURL: URL | string, inputURL: URL | string, callID: string) { if (!serverURL || !inputURL || !callID) { return false; @@ -195,7 +201,7 @@ function isCallsPopOutURL(serverURL: URL | string, inputURL: URL | string, callI return false; } - const matches = parsedURL.pathname.match(new RegExp(`^${server.subpath}([A-Za-z0-9-_]+)/`, 'i')); + const matches = parsedURL.pathname.match(new RegExp(`^${escapeRegExp(server.subpath)}([A-Za-z0-9-_]+)/`, 'i')); if (matches?.length !== 2) { return false; } @@ -224,4 +230,5 @@ export default { cleanPathName, startsWithProtocol, isCallsPopOutURL, + escapeRegExp, };