diff --git a/src/v0/util/index.js b/src/v0/util/index.js index 32872cc5d9..ac1bacf404 100644 --- a/src/v0/util/index.js +++ b/src/v0/util/index.js @@ -1328,12 +1328,19 @@ 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 (!exclusionFields.includes(k) && !isReservedWord(k)) { + mappingKeys.push(k); + } }); mappingKeys.forEach((mappingKey) => { if (!(typeof messageContext[mappingKey] === 'undefined')) { @@ -1344,7 +1351,9 @@ 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) && !isReservedWord(k)) { + 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..c34d513325 100644 --- a/src/v0/util/index.test.js +++ b/src/v0/util/index.test.js @@ -506,3 +506,187 @@ describe('validateEventAndLowerCaseConversion Tests', () => { }).toThrow(InstrumentationError); }); }); + +describe('extractCustomFields', () => { + // Handle reserved words in message keys + 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: { + 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', + ]; + + 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', + }); + }); +});