sanitize string before used in regex to prevent crash (#2219)
authorAjay Bura <32841439+ajbura@users.noreply.github.com>
Thu, 20 Feb 2025 07:30:54 +0000 (18:30 +1100)
committerGitHub <noreply@github.com>
Thu, 20 Feb 2025 07:30:54 +0000 (18:30 +1100)
src/app/components/editor/output.ts
src/app/hooks/useAsyncSearch.ts
src/app/plugins/react-custom-html-parser.tsx
src/app/utils/regex.ts

index d6136d99dcb997b1ccaeccdc4eb1debf6394c6e1..c5ecc6de618996016c1f7660874ca3f53d7d3ba1 100644 (file)
@@ -5,6 +5,7 @@ import { BlockType } from './types';
 import { CustomElement } from './slate';
 import { parseBlockMD, parseInlineMD } from '../../plugins/markdown';
 import { findAndReplace } from '../../utils/findAndReplace';
+import { sanitizeForRegex } from '../../utils/regex';
 
 export type OutputOptions = {
   allowTextFormatting?: boolean;
@@ -179,7 +180,7 @@ export const customHtmlEqualsPlainText = (customHtml: string, plain: string): bo
 export const trimCustomHtml = (customHtml: string) => customHtml.replace(/<br\/>$/g, '').trim();
 
 export const trimCommand = (cmdName: string, str: string) => {
-  const cmdRegX = new RegExp(`^(\\s+)?(\\/${cmdName})([^\\S\n]+)?`);
+  const cmdRegX = new RegExp(`^(\\s+)?(\\/${sanitizeForRegex(cmdName)})([^\\S\n]+)?`);
 
   const match = str.match(cmdRegX);
   if (!match) return str;
index 3fe7ee58901788ca7cec4c0b076da85ed2c2fe6d..3852d3b97e1abd8ec4f604161b1e406d530091fe 100644 (file)
@@ -10,6 +10,7 @@ import {
   matchQuery,
   ResultHandler,
 } from '../utils/AsyncSearch';
+import { sanitizeForRegex } from '../utils/regex';
 
 export type UseAsyncSearchOptions = AsyncSearchOption & {
   matchOptions?: MatchQueryOption;
@@ -55,8 +56,8 @@ export const orderSearchItems = <TSearchItem extends object | string | number>(
 
   // we will consider "_" as word boundary char.
   // because in more use-cases it is used. (like: emojishortcode)
-  const boundaryRegex = new RegExp(`(\\b|_)${query}`);
-  const perfectBoundaryRegex = new RegExp(`(\\b|_)${query}(\\b|_)`);
+  const boundaryRegex = new RegExp(`(\\b|_)${sanitizeForRegex(query)}`);
+  const perfectBoundaryRegex = new RegExp(`(\\b|_)${sanitizeForRegex(query)}(\\b|_)`);
 
   orderedItems.sort((i1, i2) => {
     const str1 = performMatch(getItemStr(i1, query), query, options);
index 6a4d05306872b7cba89262fe7ea0a77273e2d4dc..cd683e36581173a6d52f61c4572fd2d59d1f362f 100644 (file)
@@ -21,7 +21,7 @@ import {
   mxcUrlToHttp,
 } from '../utils/matrix';
 import { getMemberDisplayName } from '../utils/room';
-import { EMOJI_PATTERN, URL_NEG_LB } from '../utils/regex';
+import { EMOJI_PATTERN, sanitizeForRegex, URL_NEG_LB } from '../utils/regex';
 import { getHexcodeForEmoji, getShortcodeFor } from './emoji';
 import { findAndReplace } from '../utils/findAndReplace';
 import {
@@ -171,7 +171,7 @@ export const scaleSystemEmoji = (text: string): (string | JSX.Element)[] =>
   );
 
 export const makeHighlightRegex = (highlights: string[]): RegExp | undefined => {
-  const pattern = highlights.join('|');
+  const pattern = highlights.map(sanitizeForRegex).join('|');
   if (!pattern) return undefined;
   return new RegExp(pattern, 'gi');
 };
index d7169062dd4281af9bfba0bef96bb24b1650ba5a..0b98b0e2b33dd2b90434ee0a4ea347649ca48291 100644 (file)
@@ -1,3 +1,9 @@
+/**
+ * https://www.npmjs.com/package/escape-string-regexp
+ */
+export const sanitizeForRegex = (unsafeText: string): string =>
+  unsafeText.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&').replace(/-/g, '\\x2d');
+
 export const HTTP_URL_PATTERN = `https?:\\/\\/(?:www\\.)?(?:[^\\s)]*)(?<![.,:;!/?()[\\]\\s]+)`;
 
 export const URL_REG = new RegExp(HTTP_URL_PATTERN, 'g');