mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
packages/grafana-data/text: Improve escaping for special characters (#47066)
FilterInput escapes all input strings for special characters that might be used in a RegExp by calling escapeStringForRegex, and using unEscapeStringFromRegex for display. Both of these functions used string.prototype.replace() for escaping. replace() only replaces the first occurence of a search string unless called with a global RegExp. The output of these functions was not necessarily safe to compile into a RegExp literal. This change creates RegExps for escapeStringForRegex and unEscapeStringFromRegex to match all occurrences of the special characters instead of just their first occurrence. This makes a variety of strings safe for RegExp compilation.
This commit is contained in:
parent
5a87d12e8c
commit
c5cfc1645a
@ -57,12 +57,32 @@ describe('stringToMs', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('[un]escapeStringForRegex', () => {
|
||||
it.each([
|
||||
'[]',
|
||||
'\\',
|
||||
'[(abc])',
|
||||
'onetwothree',
|
||||
'<namedgroup}(this is not a regex>',
|
||||
'string\\with\\backslash',
|
||||
'everyspecialchar([{])}.,/?&*-^&<>#',
|
||||
])('should be symmetric', (input) => {
|
||||
const output = unEscapeStringFromRegex(escapeStringForRegex(input));
|
||||
expect(output).toEqual(input);
|
||||
});
|
||||
});
|
||||
|
||||
describe('escapeStringForRegex', () => {
|
||||
describe('when using a string with special chars', () => {
|
||||
it('then all special chars should be escaped', () => {
|
||||
const result = escapeStringForRegex('([{}])|*+-.?<>#&^$');
|
||||
expect(result).toBe('\\(\\[\\{\\}\\]\\)\\|\\*\\+\\-\\.\\?\\<\\>\\#\\&\\^\\$');
|
||||
});
|
||||
it.each([
|
||||
'[[[',
|
||||
'[]\\',
|
||||
'[(abc])',
|
||||
'onetwothree',
|
||||
'<namedgroup}(this is not a regex>',
|
||||
'string\\with\\backslash',
|
||||
'everyspecialchar([{])}.,/?&*-^&<>#',
|
||||
])('should always produce output that compiles', (value) => {
|
||||
expect(() => new RegExp(escapeStringForRegex(value))).not.toThrowError();
|
||||
});
|
||||
|
||||
describe('when using a string without special chars', () => {
|
||||
|
@ -1,12 +1,16 @@
|
||||
import { camelCase } from 'lodash';
|
||||
const specialChars = ['(', '[', '{', '}', ']', ')', '|', '*', '+', '-', '.', '?', '<', '>', '#', '&', '^', '$'];
|
||||
|
||||
const specialChars = ['(', '[', '{', '}', ']', ')', '\\', '|', '*', '+', '-', '.', '?', '<', '>', '#', '&', '^', '$'];
|
||||
const specialMatcher = '([\\' + specialChars.join('\\') + '])';
|
||||
const specialCharEscape = new RegExp(specialMatcher, 'g');
|
||||
const specialCharUnescape = new RegExp('(\\\\)' + specialMatcher, 'g');
|
||||
|
||||
export const escapeStringForRegex = (value: string) => {
|
||||
if (!value) {
|
||||
return value;
|
||||
}
|
||||
|
||||
return specialChars.reduce((escaped, currentChar) => escaped.replace(currentChar, '\\' + currentChar), value);
|
||||
return value.replace(specialCharEscape, '\\$1');
|
||||
};
|
||||
|
||||
export const unEscapeStringFromRegex = (value: string) => {
|
||||
@ -14,7 +18,7 @@ export const unEscapeStringFromRegex = (value: string) => {
|
||||
return value;
|
||||
}
|
||||
|
||||
return specialChars.reduce((escaped, currentChar) => escaped.replace('\\' + currentChar, currentChar), value);
|
||||
return value.replace(specialCharUnescape, '$2');
|
||||
};
|
||||
|
||||
export function stringStartsAsRegEx(str: string): boolean {
|
||||
|
Loading…
Reference in New Issue
Block a user