From 152d3f6f9b39b5aa08c72f86297f612d6fa5ecdf Mon Sep 17 00:00:00 2001 From: Luca Forstner Date: Mon, 20 Jan 2025 15:39:17 +0000 Subject: [PATCH 1/6] feat!: Only collect ip addresses with `sendDefaultPii: true` --- packages/browser-utils/src/metrics/utils.ts | 4 ++-- packages/browser/src/client.ts | 22 +++++++++++-------- packages/core/src/integrations/requestdata.ts | 8 ++++--- 3 files changed, 20 insertions(+), 14 deletions(-) diff --git a/packages/browser-utils/src/metrics/utils.ts b/packages/browser-utils/src/metrics/utils.ts index 2bc97d588395..91aefa8a8918 100644 --- a/packages/browser-utils/src/metrics/utils.ts +++ b/packages/browser-utils/src/metrics/utils.ts @@ -74,7 +74,7 @@ export function startStandaloneWebVitalSpan(options: StandaloneWebVitalSpanOptio const { name, transaction, attributes: passedAttributes, startTime } = options; - const { release, environment } = client.getOptions(); + const { release, environment, sendDefaultPii } = client.getOptions(); // We need to get the replay, user, and activeTransaction from the current scope // so that we can associate replay id, profile id, and a user display to the span const replay = client.getIntegrationByName string }>('Replay'); @@ -109,7 +109,7 @@ export function startStandaloneWebVitalSpan(options: StandaloneWebVitalSpanOptio 'user_agent.original': WINDOW.navigator?.userAgent, // This tells Sentry to infer the IP address from the request - 'client.address': '{{auto}}', + 'client.address': sendDefaultPii ? '{{auto}}' : undefined, ...passedAttributes, }; diff --git a/packages/browser/src/client.ts b/packages/browser/src/client.ts index 801a1bffbd2e..10d1abfb657a 100644 --- a/packages/browser/src/client.ts +++ b/packages/browser/src/client.ts @@ -85,19 +85,23 @@ export class BrowserClient extends Client { } this.on('postprocessEvent', event => { - addAutoIpAddressToUser(event); + if (this._options.sendDefaultPii) { + addAutoIpAddressToUser(event); + } }); this.on('beforeSendSession', session => { - if ('aggregates' in session) { - if (session.attrs?.['ip_address'] === undefined) { - session.attrs = { - ...session.attrs, - ip_address: '{{auto}}', - }; + if (this._options.sendDefaultPii) { + if ('aggregates' in session) { + if (session.attrs?.['ip_address'] === undefined) { + session.attrs = { + ...session.attrs, + ip_address: '{{auto}}', + }; + } + } else { + addAutoIpAddressToUser(session); } - } else { - addAutoIpAddressToUser(session); } }); } diff --git a/packages/core/src/integrations/requestdata.ts b/packages/core/src/integrations/requestdata.ts index 72bd02c199fb..20a290ee108f 100644 --- a/packages/core/src/integrations/requestdata.ts +++ b/packages/core/src/integrations/requestdata.ts @@ -1,3 +1,4 @@ +import { Client } from '../client'; import { defineIntegration } from '../integration'; import type { Event, IntegrationFn, RequestEventData } from '../types-hoist'; import { parseCookie } from '../utils/cookie'; @@ -38,12 +39,12 @@ const _requestDataIntegration = ((options: RequestDataIntegrationOptions = {}) = return { name: INTEGRATION_NAME, - processEvent(event) { + processEvent(event, _hint, client) { const { sdkProcessingMetadata = {} } = event; const { normalizedRequest, ipAddress } = sdkProcessingMetadata; if (normalizedRequest) { - addNormalizedRequestDataToEvent(event, normalizedRequest, { ipAddress }, include); + addNormalizedRequestDataToEvent(event, normalizedRequest, { ipAddress }, include, client); } return event; @@ -67,13 +68,14 @@ function addNormalizedRequestDataToEvent( // Data that should not go into `event.request` but is somehow related to requests additionalData: { ipAddress?: string }, include: RequestDataIncludeOptions, + client: Client, ): void { event.request = { ...event.request, ...extractNormalizedRequestData(req, include), }; - if (include.ip) { + if (include.ip || client.getOptions().sendDefaultPii) { const ip = (req.headers && getClientIPAddress(req.headers)) || additionalData.ipAddress; if (ip) { event.user = { From c86c8fd21241a89aa5d5f730536759d802eeb6b3 Mon Sep 17 00:00:00 2001 From: Luca Forstner Date: Tue, 21 Jan 2025 13:54:56 +0000 Subject: [PATCH 2/6] cleanup --- packages/browser/src/client.ts | 14 ++++++-------- packages/core/src/integrations/requestdata.ts | 11 +++++++---- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/packages/browser/src/client.ts b/packages/browser/src/client.ts index 10d1abfb657a..160cb8b9789b 100644 --- a/packages/browser/src/client.ts +++ b/packages/browser/src/client.ts @@ -84,14 +84,12 @@ export class BrowserClient extends Client { }); } - this.on('postprocessEvent', event => { - if (this._options.sendDefaultPii) { + if (this._options.sendDefaultPii) { + this.on('postprocessEvent', event => { addAutoIpAddressToUser(event); - } - }); + }); - this.on('beforeSendSession', session => { - if (this._options.sendDefaultPii) { + this.on('beforeSendSession', session => { if ('aggregates' in session) { if (session.attrs?.['ip_address'] === undefined) { session.attrs = { @@ -102,8 +100,8 @@ export class BrowserClient extends Client { } else { addAutoIpAddressToUser(session); } - } - }); + }); + } } /** diff --git a/packages/core/src/integrations/requestdata.ts b/packages/core/src/integrations/requestdata.ts index 20a290ee108f..eea701be09f3 100644 --- a/packages/core/src/integrations/requestdata.ts +++ b/packages/core/src/integrations/requestdata.ts @@ -1,4 +1,3 @@ -import { Client } from '../client'; import { defineIntegration } from '../integration'; import type { Event, IntegrationFn, RequestEventData } from '../types-hoist'; import { parseCookie } from '../utils/cookie'; @@ -43,8 +42,13 @@ const _requestDataIntegration = ((options: RequestDataIntegrationOptions = {}) = const { sdkProcessingMetadata = {} } = event; const { normalizedRequest, ipAddress } = sdkProcessingMetadata; + const includeWithDefaultPiiApplied: RequestDataIncludeOptions = { + ...include, + ip: include.ip || client.getOptions().sendDefaultPii, + }; + if (normalizedRequest) { - addNormalizedRequestDataToEvent(event, normalizedRequest, { ipAddress }, include, client); + addNormalizedRequestDataToEvent(event, normalizedRequest, { ipAddress }, includeWithDefaultPiiApplied); } return event; @@ -68,14 +72,13 @@ function addNormalizedRequestDataToEvent( // Data that should not go into `event.request` but is somehow related to requests additionalData: { ipAddress?: string }, include: RequestDataIncludeOptions, - client: Client, ): void { event.request = { ...event.request, ...extractNormalizedRequestData(req, include), }; - if (include.ip || client.getOptions().sendDefaultPii) { + if (include.ip) { const ip = (req.headers && getClientIPAddress(req.headers)) || additionalData.ipAddress; if (ip) { event.user = { From 531dff14a7bbd346bbd1220cefd409a4f2a3a22f Mon Sep 17 00:00:00 2001 From: Luca Forstner Date: Tue, 21 Jan 2025 14:15:10 +0000 Subject: [PATCH 3/6] . --- .../suites/feedback/attachTo/test.ts | 3 --- .../suites/feedback/captureFeedback/test.ts | 3 --- .../hasSampling/test.ts | 3 --- .../feedback/captureFeedbackCsp/test.ts | 3 --- .../manual-client/browser-context/test.ts | 3 --- .../suites/public-api/setUser/init.js | 1 + .../public-api/setUser/unset_user/test.ts | 4 ++++ .../standalone-mixed-transaction/test.ts | 3 --- .../suites/public-api/withScope/init.js | 1 + .../withScope/nested_scopes/test.ts | 24 +++++++++++++++---- .../suites/replay/captureReplay/test.ts | 6 ----- .../captureReplayFromReplayPackage/test.ts | 6 ----- .../web-vitals-cls-standalone-spans/test.ts | 4 ---- .../metrics/web-vitals-inp-late/test.ts | 1 - .../web-vitals-inp-parametrized-late/test.ts | 1 - .../web-vitals-inp-parametrized/test.ts | 1 - .../tracing/metrics/web-vitals-inp/test.ts | 1 - .../utils/replayEventTemplates.ts | 3 --- .../test-applications/react-17/src/index.tsx | 1 + .../react-router-6/src/index.tsx | 1 + .../react-router-7-spa/src/main.tsx | 1 + 21 files changed, 28 insertions(+), 46 deletions(-) diff --git a/dev-packages/browser-integration-tests/suites/feedback/attachTo/test.ts b/dev-packages/browser-integration-tests/suites/feedback/attachTo/test.ts index 177d8cc2994f..a9888ad6edf6 100644 --- a/dev-packages/browser-integration-tests/suites/feedback/attachTo/test.ts +++ b/dev-packages/browser-integration-tests/suites/feedback/attachTo/test.ts @@ -57,9 +57,6 @@ sentryTest('should capture feedback with custom button', async ({ getLocalTestUr event_id: expect.stringMatching(/\w{32}/), environment: 'production', tags: {}, - user: { - ip_address: '{{auto}}', - }, sdk: { integrations: expect.arrayContaining(['Feedback']), version: expect.any(String), diff --git a/dev-packages/browser-integration-tests/suites/feedback/captureFeedback/test.ts b/dev-packages/browser-integration-tests/suites/feedback/captureFeedback/test.ts index 68c45e2c2f2f..138e7225a7c8 100644 --- a/dev-packages/browser-integration-tests/suites/feedback/captureFeedback/test.ts +++ b/dev-packages/browser-integration-tests/suites/feedback/captureFeedback/test.ts @@ -69,9 +69,6 @@ sentryTest('should capture feedback', async ({ getLocalTestUrl, page }) => { 'User-Agent': expect.stringContaining(''), }, }, - user: { - ip_address: '{{auto}}', - }, platform: 'javascript', }); }); diff --git a/dev-packages/browser-integration-tests/suites/feedback/captureFeedbackAndReplay/hasSampling/test.ts b/dev-packages/browser-integration-tests/suites/feedback/captureFeedbackAndReplay/hasSampling/test.ts index c91be3511d0a..51374ac81947 100644 --- a/dev-packages/browser-integration-tests/suites/feedback/captureFeedbackAndReplay/hasSampling/test.ts +++ b/dev-packages/browser-integration-tests/suites/feedback/captureFeedbackAndReplay/hasSampling/test.ts @@ -103,9 +103,6 @@ sentryTest('should capture feedback', async ({ forceFlushReplay, getLocalTestUrl 'User-Agent': expect.stringContaining(''), }, }, - user: { - ip_address: '{{auto}}', - }, platform: 'javascript', }); }); diff --git a/dev-packages/browser-integration-tests/suites/feedback/captureFeedbackCsp/test.ts b/dev-packages/browser-integration-tests/suites/feedback/captureFeedbackCsp/test.ts index 56ba6606c724..77eadb71173a 100644 --- a/dev-packages/browser-integration-tests/suites/feedback/captureFeedbackCsp/test.ts +++ b/dev-packages/browser-integration-tests/suites/feedback/captureFeedbackCsp/test.ts @@ -69,9 +69,6 @@ sentryTest('should capture feedback', async ({ getLocalTestUrl, page }) => { 'User-Agent': expect.stringContaining(''), }, }, - user: { - ip_address: '{{auto}}', - }, platform: 'javascript', }); const cspViolation = await page.evaluate('window.__CSPVIOLATION__'); diff --git a/dev-packages/browser-integration-tests/suites/manual-client/browser-context/test.ts b/dev-packages/browser-integration-tests/suites/manual-client/browser-context/test.ts index a220ba2923d6..642006f4c2fc 100644 --- a/dev-packages/browser-integration-tests/suites/manual-client/browser-context/test.ts +++ b/dev-packages/browser-integration-tests/suites/manual-client/browser-context/test.ts @@ -34,9 +34,6 @@ sentryTest('allows to setup a client manually & capture exceptions', async ({ ge 'User-Agent': expect.any(String), }), }, - user: { - ip_address: '{{auto}}', - }, timestamp: expect.any(Number), environment: 'local', release: '0.0.1', diff --git a/dev-packages/browser-integration-tests/suites/public-api/setUser/init.js b/dev-packages/browser-integration-tests/suites/public-api/setUser/init.js index d8c94f36fdd0..1f66b52852eb 100644 --- a/dev-packages/browser-integration-tests/suites/public-api/setUser/init.js +++ b/dev-packages/browser-integration-tests/suites/public-api/setUser/init.js @@ -4,4 +4,5 @@ window.Sentry = Sentry; Sentry.init({ dsn: 'https://public@dsn.ingest.sentry.io/1337', + sendDefaultPii: true, }); diff --git a/dev-packages/browser-integration-tests/suites/public-api/setUser/unset_user/test.ts b/dev-packages/browser-integration-tests/suites/public-api/setUser/unset_user/test.ts index 43bc03bfb4d1..6fbdf6491d69 100644 --- a/dev-packages/browser-integration-tests/suites/public-api/setUser/unset_user/test.ts +++ b/dev-packages/browser-integration-tests/suites/public-api/setUser/unset_user/test.ts @@ -10,6 +10,8 @@ sentryTest('should unset user', async ({ getLocalTestUrl, page }) => { const eventData = await getMultipleSentryEnvelopeRequests(page, 3, { url }); expect(eventData[0].message).toBe('no_user'); + + // because sendDefaultPii: true expect(eventData[0].user).toEqual({ ip_address: '{{auto}}' }); expect(eventData[1].message).toBe('user'); @@ -20,6 +22,8 @@ sentryTest('should unset user', async ({ getLocalTestUrl, page }) => { }); expect(eventData[2].message).toBe('unset_user'); + + // because sendDefaultPii: true expect(eventData[2].user).toEqual({ ip_address: '{{auto}}', }); diff --git a/dev-packages/browser-integration-tests/suites/public-api/startSpan/standalone-mixed-transaction/test.ts b/dev-packages/browser-integration-tests/suites/public-api/startSpan/standalone-mixed-transaction/test.ts index 9c4c83bf6764..0663d16b6995 100644 --- a/dev-packages/browser-integration-tests/suites/public-api/startSpan/standalone-mixed-transaction/test.ts +++ b/dev-packages/browser-integration-tests/suites/public-api/startSpan/standalone-mixed-transaction/test.ts @@ -103,9 +103,6 @@ sentryTest( headers: expect.any(Object), url: expect.any(String), }, - user: { - ip_address: '{{auto}}', - }, sdk: expect.any(Object), spans: [ { diff --git a/dev-packages/browser-integration-tests/suites/public-api/withScope/init.js b/dev-packages/browser-integration-tests/suites/public-api/withScope/init.js index d8c94f36fdd0..1f66b52852eb 100644 --- a/dev-packages/browser-integration-tests/suites/public-api/withScope/init.js +++ b/dev-packages/browser-integration-tests/suites/public-api/withScope/init.js @@ -4,4 +4,5 @@ window.Sentry = Sentry; Sentry.init({ dsn: 'https://public@dsn.ingest.sentry.io/1337', + sendDefaultPii: true, }); diff --git a/dev-packages/browser-integration-tests/suites/public-api/withScope/nested_scopes/test.ts b/dev-packages/browser-integration-tests/suites/public-api/withScope/nested_scopes/test.ts index d75b0248bd4f..bf10eed2b504 100644 --- a/dev-packages/browser-integration-tests/suites/public-api/withScope/nested_scopes/test.ts +++ b/dev-packages/browser-integration-tests/suites/public-api/withScope/nested_scopes/test.ts @@ -10,22 +10,36 @@ sentryTest('should allow nested scoping', async ({ getLocalTestUrl, page }) => { const eventData = await getMultipleSentryEnvelopeRequests(page, 5, { url }); expect(eventData[0].message).toBe('root_before'); - expect(eventData[0].user).toEqual({ id: 'qux', ip_address: '{{auto}}' }); + expect(eventData[0].user).toEqual({ + id: 'qux', + ip_address: '{{auto}}', // because sendDefaultPii: true + }); expect(eventData[0].tags).toBeUndefined(); expect(eventData[1].message).toBe('outer_before'); - expect(eventData[1].user).toEqual({ id: 'qux', ip_address: '{{auto}}' }); + expect(eventData[1].user).toEqual({ + id: 'qux', + ip_address: '{{auto}}', // because sendDefaultPii: true + }); expect(eventData[1].tags).toMatchObject({ foo: false }); expect(eventData[2].message).toBe('inner'); - expect(eventData[2].user).toEqual({ ip_address: '{{auto}}' }); + expect(eventData[2].user).toEqual({ + ip_address: '{{auto}}', // because sendDefaultPii: true + }); expect(eventData[2].tags).toMatchObject({ foo: false, bar: 10 }); expect(eventData[3].message).toBe('outer_after'); - expect(eventData[3].user).toEqual({ id: 'baz', ip_address: '{{auto}}' }); + expect(eventData[3].user).toEqual({ + id: 'baz', + ip_address: '{{auto}}', // because sendDefaultPii: true + }); expect(eventData[3].tags).toMatchObject({ foo: false }); expect(eventData[4].message).toBe('root_after'); - expect(eventData[4].user).toEqual({ id: 'qux', ip_address: '{{auto}}' }); + expect(eventData[4].user).toEqual({ + id: 'qux', + ip_address: '{{auto}}', // because sendDefaultPii: true + }); expect(eventData[4].tags).toBeUndefined(); }); diff --git a/dev-packages/browser-integration-tests/suites/replay/captureReplay/test.ts b/dev-packages/browser-integration-tests/suites/replay/captureReplay/test.ts index 9737a3908247..e581a8eacd57 100644 --- a/dev-packages/browser-integration-tests/suites/replay/captureReplay/test.ts +++ b/dev-packages/browser-integration-tests/suites/replay/captureReplay/test.ts @@ -55,9 +55,6 @@ sentryTest('should capture replays (@sentry/browser export)', async ({ getLocalT 'User-Agent': expect.stringContaining(''), }, }, - user: { - ip_address: '{{auto}}', - }, platform: 'javascript', }); @@ -96,9 +93,6 @@ sentryTest('should capture replays (@sentry/browser export)', async ({ getLocalT 'User-Agent': expect.stringContaining(''), }, }, - user: { - ip_address: '{{auto}}', - }, platform: 'javascript', }); }); diff --git a/dev-packages/browser-integration-tests/suites/replay/captureReplayFromReplayPackage/test.ts b/dev-packages/browser-integration-tests/suites/replay/captureReplayFromReplayPackage/test.ts index 1c7fe09e3c33..3a10ea72e18c 100644 --- a/dev-packages/browser-integration-tests/suites/replay/captureReplayFromReplayPackage/test.ts +++ b/dev-packages/browser-integration-tests/suites/replay/captureReplayFromReplayPackage/test.ts @@ -55,9 +55,6 @@ sentryTest('should capture replays (@sentry-internal/replay export)', async ({ g 'User-Agent': expect.stringContaining(''), }, }, - user: { - ip_address: '{{auto}}', - }, platform: 'javascript', }); @@ -96,9 +93,6 @@ sentryTest('should capture replays (@sentry-internal/replay export)', async ({ g 'User-Agent': expect.stringContaining(''), }, }, - user: { - ip_address: '{{auto}}', - }, platform: 'javascript', }); }); diff --git a/dev-packages/browser-integration-tests/suites/tracing/metrics/web-vitals-cls-standalone-spans/test.ts b/dev-packages/browser-integration-tests/suites/tracing/metrics/web-vitals-cls-standalone-spans/test.ts index 9018252f37cb..02431dae3b79 100644 --- a/dev-packages/browser-integration-tests/suites/tracing/metrics/web-vitals-cls-standalone-spans/test.ts +++ b/dev-packages/browser-integration-tests/suites/tracing/metrics/web-vitals-cls-standalone-spans/test.ts @@ -69,7 +69,6 @@ sentryTest('captures a "GOOD" CLS vital with its source as a standalone span', a transaction: expect.stringContaining('index.html'), 'user_agent.original': expect.stringContaining('Chrome'), 'sentry.pageload.span_id': expect.stringMatching(/[a-f0-9]{16}/), - 'client.address': '{{auto}}', }, description: expect.stringContaining('body > div#content > p'), exclusive_time: 0, @@ -138,7 +137,6 @@ sentryTest('captures a "MEH" CLS vital with its source as a standalone span', as transaction: expect.stringContaining('index.html'), 'user_agent.original': expect.stringContaining('Chrome'), 'sentry.pageload.span_id': expect.stringMatching(/[a-f0-9]{16}/), - 'client.address': '{{auto}}', }, description: expect.stringContaining('body > div#content > p'), exclusive_time: 0, @@ -205,7 +203,6 @@ sentryTest('captures a "POOR" CLS vital with its source as a standalone span.', transaction: expect.stringContaining('index.html'), 'user_agent.original': expect.stringContaining('Chrome'), 'sentry.pageload.span_id': expect.stringMatching(/[a-f0-9]{16}/), - 'client.address': '{{auto}}', }, description: expect.stringContaining('body > div#content > p'), exclusive_time: 0, @@ -273,7 +270,6 @@ sentryTest( transaction: expect.stringContaining('index.html'), 'user_agent.original': expect.stringContaining('Chrome'), 'sentry.pageload.span_id': expect.stringMatching(/[a-f0-9]{16}/), - 'client.address': '{{auto}}', }, description: 'Layout shift', exclusive_time: 0, diff --git a/dev-packages/browser-integration-tests/suites/tracing/metrics/web-vitals-inp-late/test.ts b/dev-packages/browser-integration-tests/suites/tracing/metrics/web-vitals-inp-late/test.ts index d151772439a1..fffa85b89ae2 100644 --- a/dev-packages/browser-integration-tests/suites/tracing/metrics/web-vitals-inp-late/test.ts +++ b/dev-packages/browser-integration-tests/suites/tracing/metrics/web-vitals-inp-late/test.ts @@ -71,7 +71,6 @@ sentryTest('should capture an INP click event span after pageload', async ({ bro 'sentry.source': 'custom', transaction: 'test-url', 'user_agent.original': expect.stringContaining('Chrome'), - 'client.address': '{{auto}}', }, measurements: { inp: { diff --git a/dev-packages/browser-integration-tests/suites/tracing/metrics/web-vitals-inp-parametrized-late/test.ts b/dev-packages/browser-integration-tests/suites/tracing/metrics/web-vitals-inp-parametrized-late/test.ts index 961f98518049..65852c734c98 100644 --- a/dev-packages/browser-integration-tests/suites/tracing/metrics/web-vitals-inp-parametrized-late/test.ts +++ b/dev-packages/browser-integration-tests/suites/tracing/metrics/web-vitals-inp-parametrized-late/test.ts @@ -74,7 +74,6 @@ sentryTest( 'sentry.source': 'custom', transaction: 'test-route', 'user_agent.original': expect.stringContaining('Chrome'), - 'client.address': '{{auto}}', }, measurements: { inp: { diff --git a/dev-packages/browser-integration-tests/suites/tracing/metrics/web-vitals-inp-parametrized/test.ts b/dev-packages/browser-integration-tests/suites/tracing/metrics/web-vitals-inp-parametrized/test.ts index 911929471ea4..5705fe6863b5 100644 --- a/dev-packages/browser-integration-tests/suites/tracing/metrics/web-vitals-inp-parametrized/test.ts +++ b/dev-packages/browser-integration-tests/suites/tracing/metrics/web-vitals-inp-parametrized/test.ts @@ -70,7 +70,6 @@ sentryTest( 'sentry.origin': 'auto.http.browser.inp', transaction: 'test-route', 'user_agent.original': expect.stringContaining('Chrome'), - 'client.address': '{{auto}}', }, measurements: { inp: { diff --git a/dev-packages/browser-integration-tests/suites/tracing/metrics/web-vitals-inp/test.ts b/dev-packages/browser-integration-tests/suites/tracing/metrics/web-vitals-inp/test.ts index 1be97e2446dc..b3435a49b002 100644 --- a/dev-packages/browser-integration-tests/suites/tracing/metrics/web-vitals-inp/test.ts +++ b/dev-packages/browser-integration-tests/suites/tracing/metrics/web-vitals-inp/test.ts @@ -69,7 +69,6 @@ sentryTest('should capture an INP click event span during pageload', async ({ br 'sentry.origin': 'auto.http.browser.inp', transaction: 'test-url', 'user_agent.original': expect.stringContaining('Chrome'), - 'client.address': '{{auto}}', }, measurements: { inp: { diff --git a/dev-packages/browser-integration-tests/utils/replayEventTemplates.ts b/dev-packages/browser-integration-tests/utils/replayEventTemplates.ts index 8455bcc34600..52dbbca1c086 100644 --- a/dev-packages/browser-integration-tests/utils/replayEventTemplates.ts +++ b/dev-packages/browser-integration-tests/utils/replayEventTemplates.ts @@ -37,9 +37,6 @@ const DEFAULT_REPLAY_EVENT = { 'User-Agent': expect.any(String), }, }, - user: { - ip_address: '{{auto}}', - }, platform: 'javascript', }; diff --git a/dev-packages/e2e-tests/test-applications/react-17/src/index.tsx b/dev-packages/e2e-tests/test-applications/react-17/src/index.tsx index 49609a988202..aab492c7388b 100644 --- a/dev-packages/e2e-tests/test-applications/react-17/src/index.tsx +++ b/dev-packages/e2e-tests/test-applications/react-17/src/index.tsx @@ -38,6 +38,7 @@ Sentry.init({ replaysOnErrorSampleRate: 0.0, tunnel: 'http://localhost:3031', + sendDefaultPii: true, }); const SentryRoutes = Sentry.withSentryReactRouterV6Routing(Routes); diff --git a/dev-packages/e2e-tests/test-applications/react-router-6/src/index.tsx b/dev-packages/e2e-tests/test-applications/react-router-6/src/index.tsx index 8c219563e5a4..76884645c4c0 100644 --- a/dev-packages/e2e-tests/test-applications/react-router-6/src/index.tsx +++ b/dev-packages/e2e-tests/test-applications/react-router-6/src/index.tsx @@ -40,6 +40,7 @@ Sentry.init({ replaysOnErrorSampleRate: 0.0, tunnel: 'http://localhost:3031', + sendDefaultPii: true, }); const SentryRoutes = Sentry.withSentryReactRouterV6Routing(Routes); diff --git a/dev-packages/e2e-tests/test-applications/react-router-7-spa/src/main.tsx b/dev-packages/e2e-tests/test-applications/react-router-7-spa/src/main.tsx index a49c2c35de9d..baf12f7ff574 100644 --- a/dev-packages/e2e-tests/test-applications/react-router-7-spa/src/main.tsx +++ b/dev-packages/e2e-tests/test-applications/react-router-7-spa/src/main.tsx @@ -39,6 +39,7 @@ Sentry.init({ replaysSessionSampleRate: 1.0, replaysOnErrorSampleRate: 0.0, tunnel: 'http://localhost:3031', + sendDefaultPii: true, }); const SentryRoutes = Sentry.withSentryReactRouterV7Routing(Routes); From dc8eb118894957c9f8d145a2639ccb688e2c74ad Mon Sep 17 00:00:00 2001 From: Luca Forstner Date: Tue, 21 Jan 2025 14:41:39 +0000 Subject: [PATCH 4/6] Add tests --- .../sendDefaultPii/errors/subject.js | 1 + .../public-api/sendDefaultPii/errors/test.ts | 11 +++++++++ .../suites/public-api/sendDefaultPii/init.js | 9 +++++++ .../sendDefaultPii/performance/subject.js | 1 + .../sendDefaultPii/performance/test.ts | 21 ++++++++++++++++ .../public-api/sendDefaultPii/replay/init.js | 20 ++++++++++++++++ .../public-api/sendDefaultPii/replay/test.ts | 24 +++++++++++++++++++ .../sendDefaultPii/sessions/init.js | 9 +++++++ .../sendDefaultPii/sessions/test.ts | 13 ++++++++++ packages/browser/src/client.ts | 23 +++++++----------- 10 files changed, 118 insertions(+), 14 deletions(-) create mode 100644 dev-packages/browser-integration-tests/suites/public-api/sendDefaultPii/errors/subject.js create mode 100644 dev-packages/browser-integration-tests/suites/public-api/sendDefaultPii/errors/test.ts create mode 100644 dev-packages/browser-integration-tests/suites/public-api/sendDefaultPii/init.js create mode 100644 dev-packages/browser-integration-tests/suites/public-api/sendDefaultPii/performance/subject.js create mode 100644 dev-packages/browser-integration-tests/suites/public-api/sendDefaultPii/performance/test.ts create mode 100644 dev-packages/browser-integration-tests/suites/public-api/sendDefaultPii/replay/init.js create mode 100644 dev-packages/browser-integration-tests/suites/public-api/sendDefaultPii/replay/test.ts create mode 100644 dev-packages/browser-integration-tests/suites/public-api/sendDefaultPii/sessions/init.js create mode 100644 dev-packages/browser-integration-tests/suites/public-api/sendDefaultPii/sessions/test.ts diff --git a/dev-packages/browser-integration-tests/suites/public-api/sendDefaultPii/errors/subject.js b/dev-packages/browser-integration-tests/suites/public-api/sendDefaultPii/errors/subject.js new file mode 100644 index 000000000000..1b632e0a9289 --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/public-api/sendDefaultPii/errors/subject.js @@ -0,0 +1 @@ +Sentry.captureException(new Error('woot')); diff --git a/dev-packages/browser-integration-tests/suites/public-api/sendDefaultPii/errors/test.ts b/dev-packages/browser-integration-tests/suites/public-api/sendDefaultPii/errors/test.ts new file mode 100644 index 000000000000..310085607b09 --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/public-api/sendDefaultPii/errors/test.ts @@ -0,0 +1,11 @@ +import { expect } from '@playwright/test'; +import type { Event } from '@sentry/core'; + +import { sentryTest } from '../../../../utils/fixtures'; +import { getFirstSentryEnvelopeRequest } from '../../../../utils/helpers'; + +sentryTest('should default user to {{auto}} on errors when sendDefaultPii: true', async ({ getLocalTestUrl, page }) => { + const url = await getLocalTestUrl({ testDir: __dirname }); + const eventData = await getFirstSentryEnvelopeRequest(page, url); + expect(eventData.user?.ip_address).toBe('{{auto}}'); +}); diff --git a/dev-packages/browser-integration-tests/suites/public-api/sendDefaultPii/init.js b/dev-packages/browser-integration-tests/suites/public-api/sendDefaultPii/init.js new file mode 100644 index 000000000000..b876cb8a3288 --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/public-api/sendDefaultPii/init.js @@ -0,0 +1,9 @@ +import * as Sentry from '@sentry/browser'; + +window.Sentry = Sentry; + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + tracesSampleRate: 1, + sendDefaultPii: true, +}); diff --git a/dev-packages/browser-integration-tests/suites/public-api/sendDefaultPii/performance/subject.js b/dev-packages/browser-integration-tests/suites/public-api/sendDefaultPii/performance/subject.js new file mode 100644 index 000000000000..8a509ca1d99d --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/public-api/sendDefaultPii/performance/subject.js @@ -0,0 +1 @@ +Sentry.startSpan({ name: 'woot' }, () => undefined); diff --git a/dev-packages/browser-integration-tests/suites/public-api/sendDefaultPii/performance/test.ts b/dev-packages/browser-integration-tests/suites/public-api/sendDefaultPii/performance/test.ts new file mode 100644 index 000000000000..6e1f20826548 --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/public-api/sendDefaultPii/performance/test.ts @@ -0,0 +1,21 @@ +import { expect } from '@playwright/test'; +import { sentryTest } from '../../../../utils/fixtures'; +import { + envelopeRequestParser, + shouldSkipTracingTest, + waitForTransactionRequestOnUrl, +} from '../../../../utils/helpers'; + +sentryTest( + 'should default user to {{auto}} on transactions when sendDefaultPii: true', + async ({ getLocalTestUrl, page }) => { + if (shouldSkipTracingTest()) { + sentryTest.skip(); + } + + const url = await getLocalTestUrl({ testDir: __dirname }); + const req = await waitForTransactionRequestOnUrl(page, url); + const transaction = envelopeRequestParser(req); + expect(transaction.user?.ip_address).toBe('{{auto}}'); + }, +); diff --git a/dev-packages/browser-integration-tests/suites/public-api/sendDefaultPii/replay/init.js b/dev-packages/browser-integration-tests/suites/public-api/sendDefaultPii/replay/init.js new file mode 100644 index 000000000000..b40eb0542e6b --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/public-api/sendDefaultPii/replay/init.js @@ -0,0 +1,20 @@ +import * as Sentry from '@sentry/browser'; + +window.Sentry = Sentry; + +window.Replay = Sentry.replayIntegration({ + flushMinDelay: 200, + flushMaxDelay: 200, + minReplayDuration: 0, + useCompression: false, + blockAllMedia: false, + unmask: ['.sentry-unmask, [data-sentry-unmask]'], +}); + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + replaysSessionSampleRate: 1.0, + replaysOnErrorSampleRate: 0.0, + integrations: [window.Replay], + sendDefaultPii: true, +}); diff --git a/dev-packages/browser-integration-tests/suites/public-api/sendDefaultPii/replay/test.ts b/dev-packages/browser-integration-tests/suites/public-api/sendDefaultPii/replay/test.ts new file mode 100644 index 000000000000..4f4ad6e3003a --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/public-api/sendDefaultPii/replay/test.ts @@ -0,0 +1,24 @@ +import { expect } from '@playwright/test'; + +import { sentryTest } from '../../../../utils/fixtures'; +import { getReplayEvent, shouldSkipReplayTest, waitForReplayRequest } from '../../../../utils/replayHelpers'; + +sentryTest( + 'replay recording should contain default performance spans', + async ({ getLocalTestUrl, page, browserName }) => { + // We only test this against the NPM package and replay bundles + // and only on chromium as most performance entries are only available in chromium + if (shouldSkipReplayTest() || browserName !== 'chromium') { + sentryTest.skip(); + } + + const reqPromise0 = waitForReplayRequest(page, 0); + + const url = await getLocalTestUrl({ testDir: __dirname }); + + await page.goto(url); + const replayEvent = getReplayEvent(await reqPromise0); + + expect(replayEvent.user?.ip_address).toBe('{{auto}}'); + }, +); diff --git a/dev-packages/browser-integration-tests/suites/public-api/sendDefaultPii/sessions/init.js b/dev-packages/browser-integration-tests/suites/public-api/sendDefaultPii/sessions/init.js new file mode 100644 index 000000000000..2003a9cf82eb --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/public-api/sendDefaultPii/sessions/init.js @@ -0,0 +1,9 @@ +import * as Sentry from '@sentry/browser'; + +window.Sentry = Sentry; + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + sendDefaultPii: true, + release: '1.0', +}); diff --git a/dev-packages/browser-integration-tests/suites/public-api/sendDefaultPii/sessions/test.ts b/dev-packages/browser-integration-tests/suites/public-api/sendDefaultPii/sessions/test.ts new file mode 100644 index 000000000000..898e1cd9dbec --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/public-api/sendDefaultPii/sessions/test.ts @@ -0,0 +1,13 @@ +import { expect } from '@playwright/test'; + +import { sentryTest } from '../../../../utils/fixtures'; +import { getFirstSentryEnvelopeRequest } from '../../../../utils/helpers'; + +sentryTest( + 'should default user to {{auto}} on sessions when sendDefaultPii: true', + async ({ getLocalTestUrl, page }) => { + const url = await getLocalTestUrl({ testDir: __dirname }); + const session = await getFirstSentryEnvelopeRequest(page, url); + expect((session as any).attrs.ip_address).toBe('{{auto}}'); + }, +); diff --git a/packages/browser/src/client.ts b/packages/browser/src/client.ts index 160cb8b9789b..5e583cc87c5f 100644 --- a/packages/browser/src/client.ts +++ b/packages/browser/src/client.ts @@ -86,7 +86,12 @@ export class BrowserClient extends Client { if (this._options.sendDefaultPii) { this.on('postprocessEvent', event => { - addAutoIpAddressToUser(event); + if (event.user?.ip_address === undefined) { + event.user = { + ...event.user, + ip_address: '{{auto}}', + }; + } }); this.on('beforeSendSession', session => { @@ -98,7 +103,9 @@ export class BrowserClient extends Client { }; } } else { - addAutoIpAddressToUser(session); + if (session.ipAddress === undefined) { + session.ipAddress = '{{auto}}'; + } } }); } @@ -136,15 +143,3 @@ export class BrowserClient extends Client { return super._prepareEvent(event, hint, currentScope, isolationScope); } } - -// By default, we want to infer the IP address, unless this is explicitly set to `null` -// We do this after all other processing is done -// If `ip_address` is explicitly set to `null` or a value, we leave it as is -function addAutoIpAddressToUser(objWithMaybeUser: { user?: User | null }): void { - if (objWithMaybeUser.user?.ip_address === undefined) { - objWithMaybeUser.user = { - ...objWithMaybeUser.user, - ip_address: '{{auto}}', - }; - } -} From ae240ea063706bec7e94a1b44fb283e3b933d550 Mon Sep 17 00:00:00 2001 From: Luca Forstner Date: Tue, 21 Jan 2025 14:44:53 +0000 Subject: [PATCH 5/6] format --- packages/browser/src/client.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/browser/src/client.ts b/packages/browser/src/client.ts index 5e583cc87c5f..20b43ca6ddac 100644 --- a/packages/browser/src/client.ts +++ b/packages/browser/src/client.ts @@ -8,7 +8,6 @@ import type { ParameterizedString, Scope, SeverityLevel, - User, } from '@sentry/core'; import { Client, applySdkMetadata, getSDKSource } from '@sentry/core'; import { eventFromException, eventFromMessage } from './eventbuilder'; From 238b5c88af463cd627649f8c1bb3089c13a0b09f Mon Sep 17 00:00:00 2001 From: Luca Forstner Date: Tue, 21 Jan 2025 14:48:22 +0000 Subject: [PATCH 6/6] Add migration doc entry --- docs/migration/v8-to-v9.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/migration/v8-to-v9.md b/docs/migration/v8-to-v9.md index 7eaf78ed81d4..7c6c0153e05d 100644 --- a/docs/migration/v8-to-v9.md +++ b/docs/migration/v8-to-v9.md @@ -106,6 +106,7 @@ Older Typescript versions _may_ still work, but we will not test them anymore an ### `@sentry/browser` +- The SDK no longer instructs the Sentry backend to automatically infer IP addresses by default. This means that places where you previously saw IP addresses in Sentry may now be grouped to anonymous users. Set the `sendDefaultPii` option in `Sentry.init()` to true to instruct the Sentry backend to infer IP addresses. - The `captureUserFeedback` method has been removed. Use the `captureFeedback` method instead and update the `comments` field to `message`. ### `@sentry/nextjs`