From bc0c5faf539fd5813a0652fc791b81113a1c3dbf Mon Sep 17 00:00:00 2001 From: shrouti1507 Date: Tue, 9 Apr 2024 23:50:13 +0530 Subject: [PATCH 1/2] fix: adding check for reserved key words --- src/v0/util/index.js | 23 +++++++++++++++++-- src/v0/util/index.test.js | 47 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 2 deletions(-) diff --git a/src/v0/util/index.js b/src/v0/util/index.js index 32872cc5d9..feb8e72130 100644 --- a/src/v0/util/index.js +++ b/src/v0/util/index.js @@ -1328,12 +1328,24 @@ const generateExclusionList = (mappingConfig) => */ function extractCustomFields(message, payload, keys, exclusionFields) { const mappingKeys = []; + // Define reserved words + const reservedWords = ['__proto__', 'constructor', 'prototype']; + + const isReservedWord = (key) => reservedWords.includes(key); + if (Array.isArray(keys)) { keys.forEach((key) => { const messageContext = get(message, key); if (messageContext) { Object.keys(messageContext).forEach((k) => { - if (!exclusionFields.includes(k)) mappingKeys.push(k); + if (isReservedWord(k)) { + throw new InstrumentationError( + `The property name ${k} is a reserved word. This cannot be used to build a payload`, + ); + } + if (!exclusionFields.includes(k)) { + mappingKeys.push(k); + } }); mappingKeys.forEach((mappingKey) => { if (!(typeof messageContext[mappingKey] === 'undefined')) { @@ -1344,7 +1356,14 @@ function extractCustomFields(message, payload, keys, exclusionFields) { }); } else if (keys === 'root') { Object.keys(message).forEach((k) => { - if (!exclusionFields.includes(k)) mappingKeys.push(k); + if (!exclusionFields.includes(k)) { + if (isReservedWord(k)) { + throw new InstrumentationError( + `The property name ${k} is a reserved word. This cannot be used to build a payload`, + ); + } + mappingKeys.push(k); + } }); mappingKeys.forEach((mappingKey) => { if (!(typeof message[mappingKey] === 'undefined')) { diff --git a/src/v0/util/index.test.js b/src/v0/util/index.test.js index 810eb5a9d4..e47e29313d 100644 --- a/src/v0/util/index.test.js +++ b/src/v0/util/index.test.js @@ -506,3 +506,50 @@ describe('validateEventAndLowerCaseConversion Tests', () => { }).toThrow(InstrumentationError); }); }); + +describe('extractCustomFields', () => { + // Handle reserved words in message keys + it('should handle reserved words in message keys when keys are provided', () => { + const message = { + traits: { + firstName: 'John', + lastName: 'Doe', + email: 'john.doe@example.com', + }, + context: { + traits: { + phone: '1234567890', + city: 'New York', + country: 'USA', + }, + }, + properties: { + title: 'Developer', + organization: 'ABC Company', + zip: '12345', + prototype: 'reserved', + }, + }; + + const payload = {}; + + const keys = ['properties', 'context.traits', 'traits']; + + const exclusionFields = [ + 'firstName', + 'lastName', + 'phone', + 'title', + 'organization', + 'city', + 'region', + 'country', + 'zip', + 'image', + 'timezone', + ]; + expect(() => { + utilities.extractCustomFields(message, payload, keys, exclusionFields); + }).toThrow(InstrumentationError); + }); +}); From ab583e76ddd93cc8b0d7e989316ed8a98b84cc39 Mon Sep 17 00:00:00 2001 From: shrouti1507 Date: Fri, 12 Apr 2024 12:02:29 +0530 Subject: [PATCH 2/2] fix: review comments addressed --- src/v0/util/index.js | 14 +--- src/v0/util/index.test.js | 145 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 143 insertions(+), 16 deletions(-) diff --git a/src/v0/util/index.js b/src/v0/util/index.js index feb8e72130..ac1bacf404 100644 --- a/src/v0/util/index.js +++ b/src/v0/util/index.js @@ -1338,12 +1338,7 @@ function extractCustomFields(message, payload, keys, exclusionFields) { const messageContext = get(message, key); if (messageContext) { Object.keys(messageContext).forEach((k) => { - if (isReservedWord(k)) { - throw new InstrumentationError( - `The property name ${k} is a reserved word. This cannot be used to build a payload`, - ); - } - if (!exclusionFields.includes(k)) { + if (!exclusionFields.includes(k) && !isReservedWord(k)) { mappingKeys.push(k); } }); @@ -1356,12 +1351,7 @@ function extractCustomFields(message, payload, keys, exclusionFields) { }); } else if (keys === 'root') { Object.keys(message).forEach((k) => { - if (!exclusionFields.includes(k)) { - if (isReservedWord(k)) { - throw new InstrumentationError( - `The property name ${k} is a reserved word. This cannot be used to build a payload`, - ); - } + if (!exclusionFields.includes(k) && !isReservedWord(k)) { mappingKeys.push(k); } }); diff --git a/src/v0/util/index.test.js b/src/v0/util/index.test.js index e47e29313d..c34d513325 100644 --- a/src/v0/util/index.test.js +++ b/src/v0/util/index.test.js @@ -509,18 +509,20 @@ describe('validateEventAndLowerCaseConversion Tests', () => { describe('extractCustomFields', () => { // Handle reserved words in message keys - it('should handle reserved words in message keys when keys are provided', () => { + it('should handle reserved word "prototype" in message keys when keys are provided', () => { const message = { traits: { firstName: 'John', lastName: 'Doe', email: 'john.doe@example.com', + prototype: 'reserved', }, context: { traits: { phone: '1234567890', city: 'New York', country: 'USA', + prototype: 'reserved', }, }, properties: { @@ -548,8 +550,143 @@ describe('extractCustomFields', () => { 'image', 'timezone', ]; - expect(() => { - utilities.extractCustomFields(message, payload, keys, exclusionFields); - }).toThrow(InstrumentationError); + + const result = utilities.extractCustomFields(message, payload, keys, exclusionFields); + + expect(result).toEqual({ + email: 'john.doe@example.com', + }); + }); + + it('should handle reserved word "__proto__" in message keys when keys are provided', () => { + const message = { + traits: { + firstName: 'John', + lastName: 'Doe', + email: 'john.doe@example.com', + __proto__: 'reserved', + }, + context: { + traits: { + phone: '1234567890', + city: 'New York', + country: 'USA', + __proto__: 'reserved', + }, + }, + properties: { + title: 'Developer', + organization: 'ABC Company', + zip: '12345', + __proto__: 'reserved', + }, + }; + + const payload = {}; + + const keys = ['properties', 'context.traits', 'traits']; + + const exclusionFields = [ + 'firstName', + 'lastName', + 'phone', + 'title', + 'organization', + 'city', + 'region', + 'country', + 'zip', + 'image', + 'timezone', + ]; + const result = utilities.extractCustomFields(message, payload, keys, exclusionFields); + expect(result).toEqual({ + email: 'john.doe@example.com', + }); + }); + + it('should handle reserved word "constructor" in message keys when keys are provided', () => { + const message = { + traits: { + firstName: 'John', + lastName: 'Doe', + email: 'john.doe@example.com', + constructor: 'reserved', + }, + context: { + traits: { + phone: '1234567890', + city: 'New York', + country: 'USA', + constructor: 'reserved', + }, + }, + properties: { + title: 'Developer', + organization: 'ABC Company', + zip: '12345', + constructor: 'reserved', + }, + }; + + const payload = {}; + + const keys = ['properties', 'context.traits', 'traits']; + + const exclusionFields = [ + 'firstName', + 'lastName', + 'phone', + 'title', + 'organization', + 'city', + 'region', + 'country', + 'zip', + 'image', + 'timezone', + ]; + const result = utilities.extractCustomFields(message, payload, keys, exclusionFields); + expect(result).toEqual({ + email: 'john.doe@example.com', + }); + }); + + it('should handle reserved words in message keys when key is root', () => { + const message = { + firstName: 'John', + lastName: 'Doe', + email: 'john.doe@example.com', + prototype: 'reserved', + phone: '1234567890', + city: 'New York', + country: 'USA', + __proto__: 'reserved', + constructor: 'reserved', + }; + + const payload = {}; + + const keys = 'root'; + + const exclusionFields = [ + 'firstName', + 'lastName', + 'phone', + 'title', + 'organization', + 'city', + 'region', + 'country', + 'zip', + 'image', + 'timezone', + ]; + + const result = utilities.extractCustomFields(message, payload, keys, exclusionFields); + + expect(result).toEqual({ + email: 'john.doe@example.com', + }); }); });