From 350cb373ed621461b7fcd596b3140b7f98e4b7a3 Mon Sep 17 00:00:00 2001 From: Antonis Lilis Date: Thu, 19 Dec 2024 15:23:33 +0200 Subject: [PATCH 1/5] Use regex to extract URL from DSN for filtering breadcrumbs --- packages/core/src/js/sdk.tsx | 11 +++++++++-- packages/core/test/sdk.test.ts | 13 ++----------- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/packages/core/src/js/sdk.tsx b/packages/core/src/js/sdk.tsx index 0d37fb215f..99cf43980e 100644 --- a/packages/core/src/js/sdk.tsx +++ b/packages/core/src/js/sdk.tsx @@ -67,8 +67,15 @@ export function init(passedOptions: ReactNativeOptions): void { return undefined; } try { - const url = new URL(dsn); - return `${url.protocol}//${url.host}`; + const regex = /^(https?):\/\/(?:[^@]+@)?([^/]+)(?:\/.*)?$/; + const matches = dsn.match(regex); + + if (matches) { + const [, protocol, host] = matches; + return `${protocol}://${host}`; + } + logger.error('Failed to extract url from DSN: ', dsn); + return undefined; } catch (e) { logger.error('Failed to extract url from DSN', e); return undefined; diff --git a/packages/core/test/sdk.test.ts b/packages/core/test/sdk.test.ts index 931d7fd6d3..783f631316 100644 --- a/packages/core/test/sdk.test.ts +++ b/packages/core/test/sdk.test.ts @@ -345,21 +345,15 @@ describe('Tests the SDK functionality', () => { expect(result).toBeNull(); }); - it('should keep breadcrumbs matching dsn if the url parsing fails for dsn', () => { + it('should keep breadcrumbs if the url parsing fails for dsn', () => { (getDevServer as jest.Mock).mockReturnValue({ url: 'http://localhost:8081' }); const mockBeforeBreadcrumb = (breadcrumb: Breadcrumb, _hint?: BreadcrumbHint) => { return breadcrumb; }; - // Mock the URL constructor to throw an exception for this test case - const originalURL = (global as any).URL; - jest.spyOn(global as any, 'URL').mockImplementationOnce(() => { - throw new Error('Failed to parse DSN URL'); - }); - const passedOptions = { - dsn: 'https://abc@def.ingest.sentry.io/1234567', + dsn: 'invalid-dsn', beforeBreadcrumb: mockBeforeBreadcrumb, }; @@ -373,9 +367,6 @@ describe('Tests the SDK functionality', () => { const result = usedOptions()?.beforeBreadcrumb!(breadcrumb); expect(result).toEqual(breadcrumb); - - // Restore the original URL constructor - (global as any).URL = originalURL; }); it('should keep non dev server or dsn breadcrumbs', () => { From a1ecb49a4165bed7106f84327303529d844b57f1 Mon Sep 17 00:00:00 2001 From: Antonis Lilis Date: Fri, 10 Jan 2025 10:54:13 +0200 Subject: [PATCH 2/5] Use makeDsn from core --- packages/core/src/js/sdk.tsx | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/packages/core/src/js/sdk.tsx b/packages/core/src/js/sdk.tsx index 99cf43980e..3c6fdff90c 100644 --- a/packages/core/src/js/sdk.tsx +++ b/packages/core/src/js/sdk.tsx @@ -1,6 +1,6 @@ /* eslint-disable complexity */ import type { Breadcrumb, BreadcrumbHint, Integration, Scope, SendFeedbackParams, UserFeedback } from '@sentry/core'; -import { captureFeedback, getClient, getGlobalScope, getIntegrationsToSetup, getIsolationScope, initAndBind, logger, stackParserFromStackParserOptions, withScope as coreWithScope } from '@sentry/core'; +import { captureFeedback, getClient, getGlobalScope, getIntegrationsToSetup, getIsolationScope, initAndBind, logger, makeDsn, stackParserFromStackParserOptions, withScope as coreWithScope } from '@sentry/core'; import { defaultStackParser, makeFetchTransport, @@ -66,20 +66,13 @@ export function init(passedOptions: ReactNativeOptions): void { if (!dsn) { return undefined; } - try { - const regex = /^(https?):\/\/(?:[^@]+@)?([^/]+)(?:\/.*)?$/; - const matches = dsn.match(regex); - - if (matches) { - const [, protocol, host] = matches; - return `${protocol}://${host}`; - } + const dsnComponents = makeDsn(dsn); + if (!dsnComponents) { logger.error('Failed to extract url from DSN: ', dsn); return undefined; - } catch (e) { - logger.error('Failed to extract url from DSN', e); - return undefined; } + const port = dsnComponents.port ? `:${dsnComponents.port}` : ''; + return `${dsnComponents.protocol}://${dsnComponents.host}${port}`; }; const userBeforeBreadcrumb = safeFactory(passedOptions.beforeBreadcrumb, { loggerMessage: 'The beforeBreadcrumb threw an error' }); From de712e81cc38a1b58a7e04208d64f3d2ce6a35fa Mon Sep 17 00:00:00 2001 From: Antonis Lilis Date: Tue, 14 Jan 2025 10:15:42 +0200 Subject: [PATCH 3/5] Adds port tests --- packages/core/test/sdk.test.ts | 50 +++++++++++++++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/packages/core/test/sdk.test.ts b/packages/core/test/sdk.test.ts index 2a09217dd1..9fd8df3f17 100644 --- a/packages/core/test/sdk.test.ts +++ b/packages/core/test/sdk.test.ts @@ -321,7 +321,7 @@ describe('Tests the SDK functionality', () => { expect(result).toBeNull(); }); - it('should filters out dsn breadcrumbs', () => { + it('should filter out dsn breadcrumbs', () => { (getDevServer as jest.Mock).mockReturnValue({ url: 'http://localhost:8081' }); const mockBeforeBreadcrumb = (breadcrumb: Breadcrumb, _hint?: BreadcrumbHint) => { @@ -345,6 +345,54 @@ describe('Tests the SDK functionality', () => { expect(result).toBeNull(); }); + it('should filter out dsn breadcrumbs that the ports match', () => { + (getDevServer as jest.Mock).mockReturnValue({ url: 'http://localhost:8081' }); + + const mockBeforeBreadcrumb = (breadcrumb: Breadcrumb, _hint?: BreadcrumbHint) => { + return breadcrumb; + }; + + const passedOptions = { + dsn: 'https://sentry@selfhosted.app.server:8181/1234567', + beforeBreadcrumb: mockBeforeBreadcrumb, + }; + + init(passedOptions); + + const breadcrumb: Breadcrumb = { + type: 'http', + data: { url: 'https://selfhosted.app.server:8181/api' }, + }; + + const result = usedOptions()?.beforeBreadcrumb!(breadcrumb); + + expect(result).toBeNull(); + }); + + it('should filters out dsn breadcrumbs that the ports do not match', () => { + (getDevServer as jest.Mock).mockReturnValue({ url: 'http://localhost:8081' }); + + const mockBeforeBreadcrumb = (breadcrumb: Breadcrumb, _hint?: BreadcrumbHint) => { + return breadcrumb; + }; + + const passedOptions = { + dsn: 'https://sentry@selfhosted.app.server:8181/1234567', + beforeBreadcrumb: mockBeforeBreadcrumb, + }; + + init(passedOptions); + + const breadcrumb: Breadcrumb = { + type: 'http', + data: { url: 'https://selfhosted.app.server:8080/api' }, + }; + + const result = usedOptions()?.beforeBreadcrumb!(breadcrumb); + + expect(result).toEqual(breadcrumb); + }); + it('should keep breadcrumbs if the url parsing fails for dsn', () => { (getDevServer as jest.Mock).mockReturnValue({ url: 'http://localhost:8081' }); From c3b187f380d4fe8e8d247151bbdedbe4a253b8b6 Mon Sep 17 00:00:00 2001 From: Antonis Lilis Date: Tue, 14 Jan 2025 10:20:25 +0200 Subject: [PATCH 4/5] Fix test case naming --- packages/core/test/sdk.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/test/sdk.test.ts b/packages/core/test/sdk.test.ts index 9fd8df3f17..afd6137c8a 100644 --- a/packages/core/test/sdk.test.ts +++ b/packages/core/test/sdk.test.ts @@ -369,7 +369,7 @@ describe('Tests the SDK functionality', () => { expect(result).toBeNull(); }); - it('should filters out dsn breadcrumbs that the ports do not match', () => { + it('should keep breadcrumbs if the ports do not match', () => { (getDevServer as jest.Mock).mockReturnValue({ url: 'http://localhost:8081' }); const mockBeforeBreadcrumb = (breadcrumb: Breadcrumb, _hint?: BreadcrumbHint) => { From 32943e9c7800e04effaad22da2bbbea70c395c43 Mon Sep 17 00:00:00 2001 From: Antonis Lilis Date: Thu, 16 Jan 2025 13:15:06 +0200 Subject: [PATCH 5/5] Adds changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9f720ed17d..9a32a4502e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ ### Fixes - Use proper SDK name for Session Replay tags ([#4428](https://github.com/getsentry/sentry-react-native/pull/4428)) +- Use `makeDsn` from `core` to extract the URL from DSN avoiding unimplemented `URL.protocol` errors ([#4395]https://github.com/getsentry/sentry-react-native/pull/4395) ### Changes