diff --git a/system/services/email/EmailLoggingService.cfc b/system/services/email/EmailLoggingService.cfc index d3f9302307..5f798bf056 100644 --- a/system/services/email/EmailLoggingService.cfc +++ b/system/services/email/EmailLoggingService.cfc @@ -736,10 +736,14 @@ component { ) { var fieldsToAddFromExtraData = [ "link", "code", "reason", "link_title", "link_body" ]; var extra = StructCopy( arguments.extraData ); + var userIp = arguments.userIp; + if ( isPrivateIp( userIp ) ) { + userIp = ""; + } var data = { message = arguments.messageId , activity_type = arguments.activity - , user_ip = arguments.userIp + , user_ip = userIp , user_agent = arguments.userAgent , datecreated = arguments.eventDate }; @@ -1147,4 +1151,29 @@ component { _emailStatsService = arguments.emailStatsService; } + /** + * Checks if the given IP address is a private, loopback, or local IP address. + * + * @ipAddress.hint IP address to check + */ + public boolean function isPrivateIp( required string ipAddress ) { + var ip = Trim( arguments.ipAddress ); + if ( ip == "::1" || ip == "localhost" ) { + return true; + } + // Match IPv4 private subnets (10.x, 127.x, 169.254.x, 192.168.x) + if ( ReFindNoCase( "^(10\.|127\.|169\.254\.|192\.168\.)", ip ) ) { + return true; + } + // Match IPv4 private subnet (172.16.x - 172.31.x) + if ( ReFindNoCase( "^172\.(1[6-9]|2[0-9]|3[0-1])\.", ip ) ) { + return true; + } + // Match IPv6 private/link-local ranges (fc00::/7, fe80::/10) + if ( ReFindNoCase( "^(fe[89ab][0-9a-f]:|fc[0-9a-f]{2}:|fd[0-9a-f]{2}:)", ip ) ) { + return true; + } + return false; + } + } \ No newline at end of file diff --git a/system/views/admin/emailcenter/logs/_logActivity.cfm b/system/views/admin/emailcenter/logs/_logActivity.cfm index c294fd4bed..b694e7e984 100644 --- a/system/views/admin/emailcenter/logs/_logActivity.cfm +++ b/system/views/admin/emailcenter/logs/_logActivity.cfm @@ -9,6 +9,8 @@ + +
@@ -36,7 +38,7 @@
- + #translateResource( 'cms:audittrail.item.ip' )#: #args.ipAddress# diff --git a/tests/unit/api/email/EmailLoggingServiceTest.cfc b/tests/unit/api/email/EmailLoggingServiceTest.cfc index 80d1438102..9e0d86e4b0 100644 --- a/tests/unit/api/email/EmailLoggingServiceTest.cfc +++ b/tests/unit/api/email/EmailLoggingServiceTest.cfc @@ -80,6 +80,7 @@ component extends="resources.HelperObjects.PresideBddTestCase" { messageId = messageId , activity = activity , extraData = extraData + , userIp = "8.8.8.8" ); expect( mockLogActivityDao.$callLog().insertData.len() ).toBe( 1 ); @@ -87,7 +88,7 @@ component extends="resources.HelperObjects.PresideBddTestCase" { message = messageId , activity_type = activity , extra_data = SerializeJson( extraData ) - , user_ip = cgi.remote_addr + , user_ip = "8.8.8.8" , user_agent = cgi.http_user_agent , datecreated = Now() } ]); @@ -112,6 +113,7 @@ component extends="resources.HelperObjects.PresideBddTestCase" { messageId = messageId , activity = activity , extraData = extraData + , userIp = "8.8.8.8" ); expect( mockLogActivityDao.$callLog().insertData.len() ).toBe( 1 ); @@ -119,7 +121,7 @@ component extends="resources.HelperObjects.PresideBddTestCase" { message = messageId , activity_type = activity , extra_data = SerializeJson( expectedData ) - , user_ip = cgi.remote_addr + , user_ip = "8.8.8.8" , user_agent = cgi.http_user_agent , link = extraData.link , code = extraData.code @@ -147,6 +149,7 @@ component extends="resources.HelperObjects.PresideBddTestCase" { messageId = messageId , activity = activity , extraData = extraData + , userIp = "8.8.8.8" ); expect( service.$callLog().$announceInterception.len() ).toBe( 1 ); @@ -154,7 +157,7 @@ component extends="resources.HelperObjects.PresideBddTestCase" { message = messageId , activity_type = activity , extra_data = SerializeJson( expectedData ) - , user_ip = cgi.remote_addr + , user_ip = "8.8.8.8" , user_agent = cgi.http_user_agent , link = extraData.link , code = extraData.code @@ -162,6 +165,26 @@ component extends="resources.HelperObjects.PresideBddTestCase" { , datecreated = Now() } ] ); } ); + + it( "should blank out private or loopback IP addresses when recording activity", function(){ + var service = _getService(); + var messageId = CreateUUId(); + var activity = "blah"; + var extraData = { blah=CreateUUId(), test=Now() }; + + mockLogActivityDao.$( "insertData", CreateUUId() ); + _setupMockMessageQuery( messageId ); + + service.recordActivity( + messageId = messageId + , activity = activity + , extraData = extraData + , userIp = "127.0.0.1" + ); + + expect( mockLogActivityDao.$callLog().insertData.len() ).toBe( 1 ); + expect( mockLogActivityDao.$callLog().insertData[ 1 ][ 1 ].user_ip ).toBe( "" ); + } ); } ); describe( "markAsSent()", function(){