From 4b3bea47bc63b2d7e1118ad9dd3404048eed32ba Mon Sep 17 00:00:00 2001 From: "Antony M. Kithinzi" Date: Wed, 27 Nov 2024 02:34:43 +0800 Subject: [PATCH 1/6] fix: adding a colon to the regex parser to sanitize link --- src/libs/SearchQueryUtils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/SearchQueryUtils.ts b/src/libs/SearchQueryUtils.ts index 9645cc76a037..562d9fd5e8bf 100644 --- a/src/libs/SearchQueryUtils.ts +++ b/src/libs/SearchQueryUtils.ts @@ -37,7 +37,7 @@ const operatorToCharMap = { * Returns string value wrapped in quotes "", if the value contains special characters. */ function sanitizeSearchValue(str: string) { - const regexp = /[^A-Za-z0-9_@./#&+\-\\';,"]/g; + const regexp = /[^A-Za-z0-9_@./#&+\-\\';:,"]/g; if (regexp.test(str)) { return `"${str}"`; } From 65e846ea344883702379cb246762774faa0742b3 Mon Sep 17 00:00:00 2001 From: "Antony M. Kithinzi" Date: Fri, 29 Nov 2024 20:24:39 +0300 Subject: [PATCH 2/6] Update SearchQueryUtils.ts --- src/libs/SearchQueryUtils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/SearchQueryUtils.ts b/src/libs/SearchQueryUtils.ts index daf01f4f31aa..5ce63e772bff 100644 --- a/src/libs/SearchQueryUtils.ts +++ b/src/libs/SearchQueryUtils.ts @@ -37,7 +37,7 @@ const operatorToCharMap = { * Returns string value wrapped in quotes "", if the value contains special characters. */ function sanitizeSearchValue(str: string) { - const regexp = /[^A-Za-z0-9_@./#&+\-\\';:,"]/g; + const regexp = /[^A-Za-z0-9_@./#&+\-\\';,"]/g; if (regexp.test(str)) { return `"${str}"`; } From 444870baf8f48e8fb0e414e401c77e9b2e9a5b8f Mon Sep 17 00:00:00 2001 From: "Antony M. Kithinzi" Date: Fri, 29 Nov 2024 20:26:27 +0300 Subject: [PATCH 3/6] fix: remove extra pair of quotes --- src/libs/SearchParser/searchParser.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/SearchParser/searchParser.js b/src/libs/SearchParser/searchParser.js index c94222f3a6e9..4e1238fe0b36 100644 --- a/src/libs/SearchParser/searchParser.js +++ b/src/libs/SearchParser/searchParser.js @@ -276,7 +276,7 @@ function peg$parse(input, options) { const keywordFilter = buildFilter( "eq", "keyword", - keywords.map((filter) => filter.right).flat() + keywords.map((filter) => /^".*"$/g.test(filter.right) ? filter.right.slice(1, - 1) : filter.right).flat() ); if (keywordFilter.right.length > 0) { nonKeywords.push(keywordFilter); From cb1fd22d1561fcd85cd129a25fc360bd2567ffe1 Mon Sep 17 00:00:00 2001 From: "Antony M. Kithinzi" Date: Tue, 3 Dec 2024 22:53:11 +0300 Subject: [PATCH 4/6] test: adding test cases for search queries wrapped in quotes and contain special characters --- tests/unit/SearchParserTest.ts | 100 +++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) diff --git a/tests/unit/SearchParserTest.ts b/tests/unit/SearchParserTest.ts index 2964e406b512..dc2c2960275c 100644 --- a/tests/unit/SearchParserTest.ts +++ b/tests/unit/SearchParserTest.ts @@ -382,9 +382,109 @@ const tests = [ }, ]; +/* + * Test keywords with special characters and wrapped in quotes + */ + +const keywordTests = [ + { + query: '" " " "', // Multiple whitespaces wrapped in quotes + expected: { + type: 'expense', + status: 'all', + sortBy: 'date', + sortOrder: 'desc', + filters: { + operator: 'eq', + left: 'keyword', + right: [' ', ' '], + }, + }, + }, + { + query: '"https://expensify.com" "https://new.expensify.com"', + expected: { + type: 'expense', + status: 'all', + sortBy: 'date', + sortOrder: 'desc', + filters: { + operator: 'eq', + left: 'keyword', + right: ['https://expensify.com', 'https://new.expensify.com'], + }, + }, + }, + { + query: '""https://expensify.com"" to ""https://new.expensify.com""', // Nested quotes with a colon + expected: { + type: 'expense', + status: 'all', + sortBy: 'date', + sortOrder: 'desc', + filters: { + operator: 'eq', + left: 'keyword', + right: ['"https://expensify.com"', 'to', '"https://new.expensify.com"'], + }, + }, + }, + { + query: '"""https://expensify.com" to "https://new.expensify.com"""', // Mismatched quotes + expected: { + type: 'expense', + status: 'all', + sortBy: 'date', + sortOrder: 'desc', + filters: { + operator: 'eq', + left: 'keyword', + right: ['""https://expensify.com', 'to', 'https://new.expensify.com""'], + }, + }, + }, + { + query: 'date>2024-01-01 from:usera@user.com "https://expensify.com" "https://new.expensify.com"', + expected: { + type: 'expense', + status: 'all', + sortBy: 'date', + sortOrder: 'desc', + filters: { + operator: 'and', + left: { + operator: 'and', + left: { + operator: 'gt', + left: 'date', + right: '2024-01-01', + }, + right: { + operator: 'eq', + left: 'from', + right: 'usera@user.com', + }, + }, + right: { + operator: 'eq', + left: 'keyword', + right: ['https://expensify.com', 'https://new.expensify.com'], + }, + }, + }, + }, +]; + describe('search parser', () => { test.each(tests)(`parsing: $query`, ({query, expected}) => { const result = searchParser.parse(query) as SearchQueryJSON; expect(result).toEqual(expected); }); }); + +describe('Testing search parser with special characters and wrapped in quotes.', () => { + test.each(keywordTests)(`parsing: $query`, ({query, expected}) => { + const result = searchParser.parse(query) as SearchQueryJSON; + expect(result).toEqual(expected); + }); +}); From b240ee4149ec880097e0d0cd22d2b364f2ba9034 Mon Sep 17 00:00:00 2001 From: "Antony M. Kithinzi" Date: Tue, 3 Dec 2024 22:55:00 +0300 Subject: [PATCH 5/6] refactoring... --- src/libs/SearchParser/searchParser.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/SearchParser/searchParser.js b/src/libs/SearchParser/searchParser.js index 4e1238fe0b36..76fe1a8dc3c2 100644 --- a/src/libs/SearchParser/searchParser.js +++ b/src/libs/SearchParser/searchParser.js @@ -276,7 +276,7 @@ function peg$parse(input, options) { const keywordFilter = buildFilter( "eq", "keyword", - keywords.map((filter) => /^".*"$/g.test(filter.right) ? filter.right.slice(1, - 1) : filter.right).flat() + keywords.map((filter) => filter.right.replace(/^"(.*)"$/, '$1')).flat() ); if (keywordFilter.right.length > 0) { nonKeywords.push(keywordFilter); From 82e5a9824ea4a0e1311ba1ad69d337792e5feffa Mon Sep 17 00:00:00 2001 From: "Antony M. Kithinzi" Date: Fri, 6 Dec 2024 05:23:30 +0300 Subject: [PATCH 6/6] updated regex ... --- src/libs/SearchParser/searchParser.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/SearchParser/searchParser.js b/src/libs/SearchParser/searchParser.js index 76fe1a8dc3c2..cfba2f33cce8 100644 --- a/src/libs/SearchParser/searchParser.js +++ b/src/libs/SearchParser/searchParser.js @@ -276,7 +276,7 @@ function peg$parse(input, options) { const keywordFilter = buildFilter( "eq", "keyword", - keywords.map((filter) => filter.right.replace(/^"(.*)"$/, '$1')).flat() + keywords.map((filter) => filter.right.replace(/^(['"])(.*)\1$/, '$2')).flat() ); if (keywordFilter.right.length > 0) { nonKeywords.push(keywordFilter);