From 8f41431719d7da9c45d2add3c93878064373ee32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20Alby?= Date: Thu, 7 Jul 2022 10:00:36 +0200 Subject: [PATCH] Merge pull request #8620 from overleaf/ta-analytics-attributes-validate Ignore Invalid Analytics Attributes GitOrigin-RevId: 6e3ffc1dcc6088966480ad0704a988174e4fd3fb --- .../Features/Analytics/AnalyticsManager.js | 27 +++++++++++ .../src/Analytics/AnalyticsManagerTests.js | 45 +++++++++++++++++++ 2 files changed, 72 insertions(+) diff --git a/services/web/app/src/Features/Analytics/AnalyticsManager.js b/services/web/app/src/Features/Analytics/AnalyticsManager.js index 215d43e6d9..22c068b115 100644 --- a/services/web/app/src/Features/Analytics/AnalyticsManager.js +++ b/services/web/app/src/Features/Analytics/AnalyticsManager.js @@ -131,6 +131,9 @@ function updateEditingSession(userId, projectId, countryCode, segmentation) { if (_isAnalyticsDisabled() || _isSmokeTestUser(userId)) { return } + if (!_isSegmentationValid(segmentation)) { + return + } Metrics.analyticsQueue.inc({ status: 'adding', event_type: 'editing-session', @@ -161,6 +164,12 @@ function _recordEvent( { analyticsId, userId, event, segmentation, isLoggedIn }, { delay } = {} ) { + if (!_isAttributeValid(event)) { + return + } + if (!_isSegmentationValid(segmentation)) { + return + } Metrics.analyticsQueue.inc({ status: 'adding', event_type: 'event' }) analyticsEventsQueue .add( @@ -184,6 +193,9 @@ function _recordEvent( } function _setUserProperty({ analyticsId, propertyName, propertyValue }) { + if (!_isAttributeValid(propertyName) || !_isAttributeValid(propertyValue)) { + return + } Metrics.analyticsQueue.inc({ status: 'adding', event_type: 'user-property', @@ -230,6 +242,21 @@ function _checkPropertyValue(propertyValue) { } } +function _isAttributeValid(attribute) { + return attribute && /^[a-zA-Z0-9-_.:;,/]+$/.test(attribute) +} + +function _isSegmentationValid(segmentation) { + if (!segmentation) { + return true + } + const hasAnyInvalidAttribute = [ + ...Object.keys(segmentation), + ...Object.values(segmentation), + ].some(attribute => !_isAttributeValid(attribute)) + return !hasAnyInvalidAttribute +} + function getIdsFromSession(session) { const analyticsId = _.get(session, ['analyticsId']) const userId = SessionManager.getLoggedInUserId(session) diff --git a/services/web/test/unit/src/Analytics/AnalyticsManagerTests.js b/services/web/test/unit/src/Analytics/AnalyticsManagerTests.js index 70a0a14205..796c00516a 100644 --- a/services/web/test/unit/src/Analytics/AnalyticsManagerTests.js +++ b/services/web/test/unit/src/Analytics/AnalyticsManagerTests.js @@ -106,6 +106,51 @@ describe('AnalyticsManager', function () { ) sinon.assert.notCalled(this.Queues.createScheduledJob) }) + + it('editing session segmentation is not valid', function () { + this.AnalyticsManager.updateEditingSession( + this.fakeUserId, + '789ghi', + 'fr', + { key: '' } + ) + sinon.assert.notCalled(this.analyticsEditingSessionQueue.add) + }) + + it('event is not valid', async function () { + await this.AnalyticsManager.recordEventForUser( + this.fakeUserId, + 'not an event!' + ) + sinon.assert.notCalled(this.analyticsEventsQueue.add) + }) + + it('event segmentation is not valid', async function () { + await this.AnalyticsManager.recordEventForUser( + this.fakeUserId, + 'an_event', + { not_a: 'Valid Segmentation!' } + ) + sinon.assert.notCalled(this.analyticsEventsQueue.add) + }) + + it('user property name is not valid', async function () { + await this.AnalyticsManager.setUserPropertyForUser( + this.fakeUserId, + 'an invalid property', + 'a_value' + ) + sinon.assert.notCalled(this.analyticsUserPropertiesQueue.add) + }) + + it('user property value is not valid', async function () { + await this.AnalyticsManager.setUserPropertyForUser( + this.fakeUserId, + 'a_property', + 'an invalid value' + ) + sinon.assert.notCalled(this.analyticsUserPropertiesQueue.add) + }) }) describe('queues the appropriate message for', function () {