UNPKG

@dynatrace/react-native-plugin

Version:

This plugin gives you the ability to use the Dynatrace Mobile agent in your react native application.

293 lines (292 loc) 11.9 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ModifyEventValidation = void 0; const ConsoleLogger_1 = require("../../../core/logging/ConsoleLogger"); const EventSpecContstants_1 = require("../spec/EventSpecContstants"); const EventModifierUtil_1 = require("./EventModifierUtil"); class ModifyEventValidation { constructor() { this.customEventModifierChain = []; this.logger = new ConsoleLogger_1.ConsoleLogger('ModifyEventValidation'); } addEventModifier(eventModifier) { this.customEventModifierChain.push(eventModifier); return eventModifier; } removeEventModifier(eventModifier) { const index = this.customEventModifierChain.indexOf(eventModifier); if (index !== -1) { this.customEventModifierChain.splice(index, 1); return true; } return false; } modifyEvent(event) { if (this.customEventModifierChain.length > 0) { const eventCopy = Object.assign({}, event); let exceptionOccured = false; let isDiscarded = false; for (const modifier of this.customEventModifierChain) { try { const eventRv = modifier.modifyEvent(event); if (!eventRv) { isDiscarded = true; break; } else { event = eventRv; } } catch (_a) { if (event != null) { exceptionOccured = true; } } } if (!isDiscarded) { event = this.sanitizeUserEnrichedEvent(eventCopy, event, exceptionOccured); } else { return null; } } return event; } isCustomPropertiesAllowed(key, hasSessionPropertyCharacteristics) { if (hasSessionPropertyCharacteristics) { if (key.startsWith(`${"event_properties"}.`)) { this.logger.debug(`isPropertiesAllowed(): Filtering key ${key} as usage of event properties is not allowed!`); return false; } } else { if (key.startsWith(`${"session_properties"}.`)) { this.logger.debug(`isPropertiesAllowed(): Filtering key ${key} as usage of session properties is not allowed!`); return false; } } return true; } isKeyNameForbidden(key, isAdded = false) { for (const namespace of EventSpecContstants_1.MODIFY_EVENT_WHITELIST_NAMESPACE) { if (key.startsWith(`${namespace}.`)) { return false; } } if (!isAdded) { if (EventSpecContstants_1.MODIFY_EVENT_WHITELIST_FIELDS.includes(key)) { return false; } } this.logger.debug(`isKeyNameForbidden(): Filtering key ${key} as this field is reserved and must not be overridden!`); return true; } sanitizeUserEnrichedEvent(originalEvent, userEnrichedEvent, externalException) { if (!(0, EventModifierUtil_1.isObject)(userEnrichedEvent)) { this.logger.debug(`sanitizeUserEnrichedEvent(${originalEvent}, ${userEnrichedEvent}): Enriched event is not an object`); return originalEvent; } if (userEnrichedEvent === originalEvent) { this.logger.debug(`sanitizeUserEnrichedEvent(${originalEvent}, ${userEnrichedEvent}): Event has not been changed`); return originalEvent; } let overriddenKeys = originalEvent["dt.support.api.overridden_fields"]; if (overriddenKeys == null) { overriddenKeys = []; } const userEnrichedEventEntries = Object.entries(userEnrichedEvent); const validEntries = this.determineValidEntries(userEnrichedEventEntries, originalEvent, overriddenKeys); const restoredEntries = this.restoreRemovedEntries(Object.entries(originalEvent), userEnrichedEvent, overriddenKeys); const validAndRestoredEntries = validEntries.concat(restoredEntries); const { baseEntries, addedEntries } = this.determineAddedEntries(originalEvent, validAndRestoredEntries); const limitedAddedEntries = this.validateAddedEntries(addedEntries); if (originalEvent["characteristics.has_event_properties"] === undefined && (0, EventModifierUtil_1.containEventPropertiesInArray)(limitedAddedEntries)) { limitedAddedEntries.push([ "characteristics.has_event_properties", true, ]); } const finalEntries = baseEntries.concat(limitedAddedEntries); const sizedEntries = this.enforcePropertyLimit(finalEntries); if (Array.isArray(overriddenKeys) && overriddenKeys.length > 0) { sizedEntries.push([ "dt.support.api.overridden_fields", overriddenKeys, ]); } if (externalException) { sizedEntries.push([ "dt.support.api.has_enrich_exception", true, ]); } return Object.fromEntries(sizedEntries); } determineChangedContent(modifiedJSONEventEntries, originalJSONEvent) { const changedEntries = []; for (const [prop, value] of modifiedJSONEventEntries) { const originalValue = originalJSONEvent[prop]; if (this.isModified(originalValue, value)) { changedEntries.push([prop, value]); continue; } } return changedEntries; } determineValidEntries(userEnrichedEntries, originalJSONEvent, overriddenKeys) { const validEntries = []; let droppedCustomProperties = false; let droppedProperties = false; for (const [prop, value] of userEnrichedEntries) { const originalValue = originalJSONEvent[prop]; if (!this.isModified(originalValue, value)) { validEntries.push([prop, value]); continue; } if (!this.isCustomPropertiesAllowed(prop, originalJSONEvent["characteristics.has_session_properties"] === true)) { droppedCustomProperties = true; continue; } const isNewlyAdded = typeof originalValue === 'undefined'; const isForbiddenKey = this.isKeyNameForbidden(prop, isNewlyAdded); if (isForbiddenKey) { if (!isNewlyAdded) { validEntries.push([prop, originalValue]); } droppedProperties = true; continue; } if (!isNewlyAdded && !overriddenKeys.includes(prop)) { overriddenKeys.push(prop); } if (!isNewlyAdded && EventSpecContstants_1.MODIFY_EVENT_WHITELIST_STRING_FIELDS.includes(prop)) { const maximumLength = Math.max(originalJSONEvent[prop].toString().length, EventSpecContstants_1.MAX_CUSTOM_EVENT_VALUE_LENGTH); validEntries.push([ prop, (0, EventModifierUtil_1.trimString)(prop, value.toString(), maximumLength), ]); } else { validEntries.push([prop, value]); } } if (droppedCustomProperties) { validEntries.push([ "dt.support.api.has_dropped_custom_properties", true, ]); } if (droppedProperties) { validEntries.push([ "dt.support.api.has_dropped_properties", true, ]); } return validEntries; } isModified(oldValue, newValue) { if (Array.isArray(oldValue)) { return (!Array.isArray(newValue) || oldValue.length !== newValue.length || !oldValue.every((item, index) => !this.isModified(item, newValue[index]))); } if ((0, EventModifierUtil_1.isObject)(oldValue)) { const oldEntries = Object.entries(oldValue); return (!(0, EventModifierUtil_1.isObject)(newValue) || Object.entries(newValue).length !== oldEntries.length || !oldEntries.every(([prop, value]) => !this.isModified(value, newValue[prop]))); } return oldValue !== newValue; } restoreRemovedEntries(originalEntries, userEnrichedEvent, overriddenKeys) { const restoredEntries = []; for (const [prop, value] of originalEntries) { if (typeof userEnrichedEvent[prop] !== 'undefined') { continue; } if (this.isKeyNameForbidden(prop)) { restoredEntries.push([prop, value]); } else if (!overriddenKeys.includes(prop)) { overriddenKeys.push(prop); } } return restoredEntries; } determineAddedEntries(originalJSONEvent, userEnrichedEntries) { const resultEntries = { baseEntries: [], addedEntries: [], }; return userEnrichedEntries.reduce((entries, entry) => { if (Object.prototype.hasOwnProperty.call(originalJSONEvent, entry[0])) { entries.baseEntries.push(entry); } else { entries.addedEntries.push(entry); } return entries; }, resultEntries); } validateAddedEntries(addedEntries) { const validEntries = []; let droppedProperties = false; let droppedCustomProperties = false; for (const entry of addedEntries) { if (!(0, EventModifierUtil_1.isNotObject)(entry) || !(0, EventModifierUtil_1.doesNotExceedKeySize)(entry) || !(0, EventModifierUtil_1.isKeySyntaxAllowed)(entry)) { if ((0, EventModifierUtil_1.isKeyCustomProperty)(entry[0])) { droppedCustomProperties = true; } else { droppedProperties = true; } continue; } (0, EventModifierUtil_1.restrictingValueSize)(entry); validEntries.push(entry); } if (droppedCustomProperties) { validEntries.push([ "dt.support.api.has_dropped_custom_properties", true, ]); } if (droppedProperties) { validEntries.push([ "dt.support.api.has_dropped_properties", true, ]); } return validEntries; } enforcePropertyLimit(entries) { const result = []; let propertyCount = 0; let droppedCustomProperties = false; entries.sort((a, b) => a[0].localeCompare(b[0])); for (const [key, value] of entries) { if ((0, EventModifierUtil_1.isKeyCustomProperty)(key)) { propertyCount++; if (propertyCount > EventSpecContstants_1.MAX_CUSTOM_EVENT_FIELDS) { this.logger.debug(`enforcePropertyLimit(): Dropped ${key} because overall ` + `property limit (${EventSpecContstants_1.MAX_CUSTOM_EVENT_FIELDS}) is reached!`); droppedCustomProperties = true; continue; } } result.push([key, value]); } if (droppedCustomProperties) { result.push([ "dt.support.api.has_dropped_custom_properties", true, ]); } return result; } } exports.ModifyEventValidation = ModifyEventValidation;