@dynatrace/react-native-plugin
Version:
This plugin gives you the ability to use the Dynatrace Mobile agent in your react native application.
190 lines (189 loc) • 8.1 kB
JavaScript
"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 EventLimitation_1 = require("./EventLimitation");
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;
this.customEventModifierChain.forEach((modifier) => {
try {
event = modifier.modifyEvent(event);
}
catch (error) {
if (event != null) {
exceptionOccured = true;
}
}
});
event = this.sanitizeUserEnrichedEvent(eventCopy, event, exceptionOccured);
}
return event;
}
isPropertiesAllowed(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 true;
}
}
else {
if (key.startsWith(`${"session_properties"}.`)) {
this.logger.debug(`isPropertiesAllowed(): Filtering key ${key} as usage of session properties is not allowed!`);
return true;
}
}
return false;
}
isKeyNameForbidden(key) {
for (const namespace of EventSpecContstants_1.MODIFY_EVENT_WHITELIST_NAMESPACE) {
if (key.startsWith(`${namespace}.`)) {
return false;
}
}
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.internal.api.overridden_keys"];
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 limitedEntries = new EventLimitation_1.EventLimitation().limitEventEntries(addedEntries);
if (originalEvent["characteristics.has_event_properties"] === undefined &&
(0, EventModifierUtil_1.containEventPropertiesInArray)(limitedEntries)) {
limitedEntries.push([
"characteristics.has_event_properties",
true,
]);
}
const finalEntries = baseEntries.concat(limitedEntries);
const sizedEntries = new EventLimitation_1.EventLimitation().limitEventProperties(finalEntries);
if (sizedEntries.length < userEnrichedEventEntries.length) {
sizedEntries.push([
"dt.internal.api.has_dropped_custom_properties",
true,
]);
}
if (Array.isArray(overriddenKeys) && overriddenKeys.length > 0) {
sizedEntries.push([
"dt.internal.api.overridden_keys",
overriddenKeys,
]);
}
if (externalException) {
sizedEntries.push([
"dt.internal.api.has_enrich_exception",
true,
]);
}
return Object.fromEntries(sizedEntries);
}
determineValidEntries(userEnrichedEntries, originalJSONEvent, overriddenKeys) {
const newEntries = [];
for (const [prop, value] of userEnrichedEntries) {
const originalValue = originalJSONEvent[prop];
if (!this.isModified(originalValue, value)) {
newEntries.push([prop, value]);
continue;
}
if (this.isPropertiesAllowed(prop, originalJSONEvent["characteristics.has_session_properties"] === true)) {
continue;
}
const isNewlyAdded = typeof originalValue === 'undefined';
const isForbiddenKey = this.isKeyNameForbidden(prop);
if (isForbiddenKey) {
if (!isNewlyAdded) {
newEntries.push([prop, originalValue]);
}
continue;
}
if (!isNewlyAdded && !overriddenKeys.includes(prop)) {
overriddenKeys.push(prop);
}
newEntries.push([prop, value]);
}
return newEntries;
}
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);
}
}
exports.ModifyEventValidation = ModifyEventValidation;