From 95208e96e0c2ff756404e408e5f8187134a4d45c Mon Sep 17 00:00:00 2001 From: Diamond Lewis Date: Sun, 28 Jul 2019 23:54:13 -0500 Subject: [PATCH] Postgres: Safely escape strings in nested objects (#5855) * Postgres: Safely handle string in nested objects * fix failing tests --- spec/ParseQuery.spec.js | 18 +++++++++++++++ .../Postgres/PostgresStorageAdapter.js | 22 +++++-------------- 2 files changed, 24 insertions(+), 16 deletions(-) diff --git a/spec/ParseQuery.spec.js b/spec/ParseQuery.spec.js index d5d1fc47..866d9238 100644 --- a/spec/ParseQuery.spec.js +++ b/spec/ParseQuery.spec.js @@ -359,6 +359,24 @@ describe('Parse.Query testing', () => { }, done.fail); }); + it('nested equalTo string with single quote', async () => { + const obj = new TestObject({ nested: { foo: "single'quote" } }); + await obj.save(); + const query = new Parse.Query(TestObject); + query.equalTo('nested.foo', "single'quote"); + const result = await query.get(obj.id); + equal(result.get('nested').foo, "single'quote"); + }); + + it('nested containedIn string with single quote', async () => { + const obj = new TestObject({ nested: { foo: ["single'quote"]} }); + await obj.save(); + const query = new Parse.Query(TestObject); + query.containedIn('nested.foo', ["single'quote"]); + const result = await query.get(obj.id); + equal(result.get('nested').foo[0], "single'quote"); + }); + it('nested containedIn string', done => { const sender1 = { group: ['A', 'B'] }; const sender2 = { group: ['A', 'C'] }; diff --git a/src/Adapters/Storage/Postgres/PostgresStorageAdapter.js b/src/Adapters/Storage/Postgres/PostgresStorageAdapter.js index 74026e70..9290a6d7 100644 --- a/src/Adapters/Storage/Postgres/PostgresStorageAdapter.js +++ b/src/Adapters/Storage/Postgres/PostgresStorageAdapter.js @@ -282,26 +282,16 @@ const buildWhereClause = ({ schema, query, index }): WhereClause => { patterns.push(`${name} IS NULL`); } else { if (fieldValue.$in) { - const inPatterns = []; name = transformDotFieldToComponents(fieldName).join('->'); - fieldValue.$in.forEach(listElem => { - if (typeof listElem === 'string') { - if (listElem.includes('"') || listElem.includes("'")) { - throw new Parse.Error( - Parse.Error.INVALID_JSON, - 'bad $in value; Strings with quotes cannot yet be safely escaped' - ); - } - inPatterns.push(`"${listElem}"`); - } else { - inPatterns.push(`${listElem}`); - } - }); - patterns.push(`(${name})::jsonb @> '[${inPatterns.join()}]'::jsonb`); + patterns.push(`($${index}:raw)::jsonb @> $${index + 1}::jsonb`); + values.push(name, JSON.stringify(fieldValue.$in)); + index += 2; } else if (fieldValue.$regex) { // Handle later } else { - patterns.push(`${name} = '${fieldValue}'`); + patterns.push(`$${index}:raw = $${index + 1}::text`); + values.push(name, fieldValue); + index += 2; } } } else if (fieldValue === null || fieldValue === undefined) {