From c694a19e7cc1535f0bf0c9223e2d55b8fa2bd408 Mon Sep 17 00:00:00 2001 From: Mike Bruin Date: Thu, 23 Jan 2025 10:33:32 -0500 Subject: [PATCH] moved the attribute validator to the BlockAttributeValidator class to try to address concerns. --- Agent/Analytics/BlockAttributeValidator.h | 2 + Agent/Analytics/BlockAttributeValidator.m | 63 +++++++++++++++++++ Agent/Analytics/NRMAAnalytics.mm | 2 +- .../HandledException/NRMAHandledExceptions.mm | 13 ++-- Agent/Utilities/NewRelicInternalUtils.h | 3 - Agent/Utilities/NewRelicInternalUtils.m | 60 ------------------ 6 files changed, 73 insertions(+), 70 deletions(-) diff --git a/Agent/Analytics/BlockAttributeValidator.h b/Agent/Analytics/BlockAttributeValidator.h index 81eaeaf1..41ca93f8 100644 --- a/Agent/Analytics/BlockAttributeValidator.h +++ b/Agent/Analytics/BlockAttributeValidator.h @@ -22,6 +22,8 @@ NS_ASSUME_NONNULL_BEGIN valueValidator:(ValueValidator)valueValidator andEventTypeValidator:(EventTypeValidator)eventTypeValidator; ++ (BlockAttributeValidator *) attributeValidator; + @end NS_ASSUME_NONNULL_END diff --git a/Agent/Analytics/BlockAttributeValidator.m b/Agent/Analytics/BlockAttributeValidator.m index 9122f23f..f3d5123f 100644 --- a/Agent/Analytics/BlockAttributeValidator.m +++ b/Agent/Analytics/BlockAttributeValidator.m @@ -7,6 +7,9 @@ // #import "BlockAttributeValidator.h" +#import "Constants.h" +#import "NRMAAnalytics.h" +#import "NRLogger.h" @implementation BlockAttributeValidator @@ -35,4 +38,64 @@ - (BOOL)valueValidator:(id)value { return self.valueValidator(value); } +static BlockAttributeValidator *_attributeValidator; ++ (BlockAttributeValidator *) attributeValidator +{ + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + _attributeValidator = [[BlockAttributeValidator alloc] initWithNameValidator:^BOOL(NSString *name) { + if ([name length] == 0) { + NRLOG_AGENT_ERROR(@"invalid attribute: name length = 0"); + return false; + } + if ([name hasPrefix:@" "]) { + NRLOG_AGENT_ERROR(@"invalid attribute: name prefix = \" \""); + return false; + } + // check if attribute name is reserved or attribute name matches reserved prefix. + for (NSString* key in [NRMAAnalytics reservedKeywords]) { + if ([key isEqualToString:name]) { + NRLOG_AGENT_ERROR(@"invalid attribute: name prefix disallowed"); + return false; + } + } + for (NSString* key in [NRMAAnalytics reservedPrefixes]) { + if ([name hasPrefix:key]) { + NRLOG_AGENT_ERROR(@"invalid attribute: name prefix disallowed"); + return false; + } + } + + // check if attribute name exceeds max length. + if ([name length] > kNRMA_Attrib_Max_Name_Length) { + NRLOG_AGENT_ERROR(@"invalid attribute: name length exceeds limit"); + return false; + } + return true; + + } valueValidator:^BOOL(id value) { + if ([value isKindOfClass:[NSString class]]) { + if ([(NSString*)value length] == 0) { + NRLOG_AGENT_ERROR(@"invalid attribute: value length = 0"); + return false; + } + else if ([(NSString*)value length] >= kNRMA_Attrib_Max_Value_Size_Bytes) { + NRLOG_AGENT_ERROR(@"invalid attribute: value exceeded maximum byte size exceeded"); + return false; + } + } + if (value == nil || [value isKindOfClass:[NSNull class]]) { + NRLOG_AGENT_ERROR(@"invalid attribute: value cannot be nil"); + return false; + } + + return true; + } andEventTypeValidator:^BOOL(NSString *eventType) { + return YES; + }]; + }); + + return _attributeValidator; +} + @end diff --git a/Agent/Analytics/NRMAAnalytics.mm b/Agent/Analytics/NRMAAnalytics.mm index 092d638a..a3543853 100644 --- a/Agent/Analytics/NRMAAnalytics.mm +++ b/Agent/Analytics/NRMAAnalytics.mm @@ -116,7 +116,7 @@ - (id) initWithSessionStartTimeMS:(long long) sessionStartTime { PersistentEventStore *eventStore = [[PersistentEventStore alloc] initWithFilename:filename andMinimumDelay:.025]; _eventManager = [[NRMAEventManager alloc] initWithPersistentStore:eventStore]; - _attributeValidator = [NewRelicInternalUtils attributeValidator]; + _attributeValidator = [BlockAttributeValidator attributeValidator]; _sessionAttributeManager = [[NRMASAM alloc] initWithAttributeValidator:_attributeValidator]; NSString* attributes = [self sessionAttributeJSONString]; diff --git a/Agent/HandledException/NRMAHandledExceptions.mm b/Agent/HandledException/NRMAHandledExceptions.mm index 501cc9fa..c55344e5 100644 --- a/Agent/HandledException/NRMAHandledExceptions.mm +++ b/Agent/HandledException/NRMAHandledExceptions.mm @@ -22,6 +22,7 @@ #import "NRMABool.h" #import "NRMASupportMetricHelper.h" #import "Constants.h" +#import "BlockAttributeValidator.h" @interface NRMAAnalytics(Protected) // Because the NRMAAnalytics class interfaces with non Objective-C++ files, we cannot expose the API on the header. Therefore, we must use this reference. @@ -198,7 +199,7 @@ - (void) recordError:(NSError * _Nonnull)error resultMap, [self createThreadVector:callstack length:frames] ); - NRMAExceptionReportAdaptor* contextAdapter = [[[NRMAExceptionReportAdaptor alloc] initWithReport:report attributeValidator:[NewRelicInternalUtils attributeValidator]] autorelease]; + NRMAExceptionReportAdaptor* contextAdapter = [[[NRMAExceptionReportAdaptor alloc] initWithReport:report attributeValidator:[BlockAttributeValidator attributeValidator]] autorelease]; if (attributes != nil) { [contextAdapter addAttributesNewValidation:attributes]; @@ -218,7 +219,7 @@ - (void) recordError:(NSError * _Nonnull)error [self createThreadVector:callstack length:frames] ); - NRMAExceptionReportAdaptor* contextAdapter = [[[NRMAExceptionReportAdaptor alloc] initWithReport:report attributeValidator:[NewRelicInternalUtils attributeValidator]] autorelease]; + NRMAExceptionReportAdaptor* contextAdapter = [[[NRMAExceptionReportAdaptor alloc] initWithReport:report attributeValidator:[BlockAttributeValidator attributeValidator]] autorelease]; if (attributes != nil) { [contextAdapter addAttributes:attributes]; @@ -268,7 +269,7 @@ - (void) recordHandledException:(NSException*)exception [self checkOffline:report]; - NRMAExceptionReportAdaptor* contextAdapter = [[[NRMAExceptionReportAdaptor alloc] initWithReport:report attributeValidator:[NewRelicInternalUtils attributeValidator]] autorelease]; + NRMAExceptionReportAdaptor* contextAdapter = [[[NRMAExceptionReportAdaptor alloc] initWithReport:report attributeValidator:[BlockAttributeValidator attributeValidator]] autorelease]; if (attributes != nil) { [contextAdapter addAttributesNewValidation:attributes]; @@ -287,7 +288,7 @@ - (void) recordHandledException:(NSException*)exception [self checkOffline:report]; - NRMAExceptionReportAdaptor* contextAdapter = [[[NRMAExceptionReportAdaptor alloc] initWithReport:report attributeValidator:[NewRelicInternalUtils attributeValidator]] autorelease]; + NRMAExceptionReportAdaptor* contextAdapter = [[[NRMAExceptionReportAdaptor alloc] initWithReport:report attributeValidator:[BlockAttributeValidator attributeValidator]] autorelease]; if (attributes != nil) { [contextAdapter addAttributes:attributes]; @@ -371,7 +372,7 @@ - (void) recordHandledExceptionWithStackTrace:(NSDictionary*)exceptionDictionary report->setAttributeNoValidation("timeSinceLoad", [[[NSDate new] autorelease] timeIntervalSinceDate:self.sessionStartDate]); [self checkOffline:report]; - NRMAExceptionReportAdaptor* contextAdapter = [[[NRMAExceptionReportAdaptor alloc] initWithReport:report attributeValidator:[NewRelicInternalUtils attributeValidator]] autorelease]; + NRMAExceptionReportAdaptor* contextAdapter = [[[NRMAExceptionReportAdaptor alloc] initWithReport:report attributeValidator:[BlockAttributeValidator attributeValidator]] autorelease]; if (exceptionDictionary != nil) { [contextAdapter addAttributesNewValidation:exceptionDictionary]; @@ -388,7 +389,7 @@ - (void) recordHandledExceptionWithStackTrace:(NSDictionary*)exceptionDictionary report->setAttribute("timeSinceLoad", [[[NSDate new] autorelease] timeIntervalSinceDate:self.sessionStartDate]); [self checkOffline:report]; - NRMAExceptionReportAdaptor* contextAdapter = [[[NRMAExceptionReportAdaptor alloc] initWithReport:report attributeValidator:[NewRelicInternalUtils attributeValidator]] autorelease]; + NRMAExceptionReportAdaptor* contextAdapter = [[[NRMAExceptionReportAdaptor alloc] initWithReport:report attributeValidator:[BlockAttributeValidator attributeValidator]] autorelease]; if (exceptionDictionary != nil) { [contextAdapter addAttributes:exceptionDictionary]; diff --git a/Agent/Utilities/NewRelicInternalUtils.h b/Agent/Utilities/NewRelicInternalUtils.h index 2d391156..7eece589 100644 --- a/Agent/Utilities/NewRelicInternalUtils.h +++ b/Agent/Utilities/NewRelicInternalUtils.h @@ -9,7 +9,6 @@ #import "NRMAReachability.h" #import "NRConstants.h" #import "NRMANetworkMonitor.h" -#import "BlockAttributeValidator.h" #if __LP64__ #define NRMA_NSI "ld" @@ -105,7 +104,5 @@ NSTimeInterval NRMAMillisecondTimestamp(void); + (NRMAReachability*) reachability; -+ (id) attributeValidator; - @end diff --git a/Agent/Utilities/NewRelicInternalUtils.m b/Agent/Utilities/NewRelicInternalUtils.m index 677f9fc8..c0f8d182 100644 --- a/Agent/Utilities/NewRelicInternalUtils.m +++ b/Agent/Utilities/NewRelicInternalUtils.m @@ -689,64 +689,4 @@ + (BOOL) isSimulator { return simulator != nil; } -static id _attributeValidator; -+ (id) attributeValidator -{ - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - _attributeValidator = [[BlockAttributeValidator alloc] initWithNameValidator:^BOOL(NSString *name) { - if ([name length] == 0) { - NRLOG_AGENT_ERROR(@"invalid attribute: name length = 0"); - return false; - } - if ([name hasPrefix:@" "]) { - NRLOG_AGENT_ERROR(@"invalid attribute: name prefix = \" \""); - return false; - } - // check if attribute name is reserved or attribute name matches reserved prefix. - for (NSString* key in [NRMAAnalytics reservedKeywords]) { - if ([key isEqualToString:name]) { - NRLOG_AGENT_ERROR(@"invalid attribute: name prefix disallowed"); - return false; - } - } - for (NSString* key in [NRMAAnalytics reservedPrefixes]) { - if ([name hasPrefix:key]) { - NRLOG_AGENT_ERROR(@"invalid attribute: name prefix disallowed"); - return false; - } - } - - // check if attribute name exceeds max length. - if ([name length] > kNRMA_Attrib_Max_Name_Length) { - NRLOG_AGENT_ERROR(@"invalid attribute: name length exceeds limit"); - return false; - } - return true; - - } valueValidator:^BOOL(id value) { - if ([value isKindOfClass:[NSString class]]) { - if ([(NSString*)value length] == 0) { - NRLOG_AGENT_ERROR(@"invalid attribute: value length = 0"); - return false; - } - else if ([(NSString*)value length] >= kNRMA_Attrib_Max_Value_Size_Bytes) { - NRLOG_AGENT_ERROR(@"invalid attribute: value exceeded maximum byte size exceeded"); - return false; - } - } - if (value == nil || [value isKindOfClass:[NSNull class]]) { - NRLOG_AGENT_ERROR(@"invalid attribute: value cannot be nil"); - return false; - } - - return true; - } andEventTypeValidator:^BOOL(NSString *eventType) { - return YES; - }]; - }); - - return _attributeValidator; -} - @end