diff --git a/packages/instrumentation/src/navigation/index.ts b/packages/instrumentation/src/navigation/index.ts index c20c9b7..b9d9ceb 100644 --- a/packages/instrumentation/src/navigation/index.ts +++ b/packages/instrumentation/src/navigation/index.ts @@ -2,10 +2,8 @@ * Copyright The OpenTelemetry Authors * SPDX-License-Identifier: Apache-2.0 */ - export { NavigationInstrumentation } from './instrumentation.ts'; export type { NavigationInstrumentationConfig, NavigationType, } from './types.ts'; -export { defaultSanitizeUrl } from './utils.ts'; diff --git a/packages/instrumentation/src/navigation/instrumentation.test.ts b/packages/instrumentation/src/navigation/instrumentation.test.ts index 9984963..f18f189 100644 --- a/packages/instrumentation/src/navigation/instrumentation.test.ts +++ b/packages/instrumentation/src/navigation/instrumentation.test.ts @@ -13,7 +13,9 @@ import { it, vi, } from 'vitest'; +import { defaultSanitizeUrl } from '#utils'; import { setupTestLogExporter } from '#utils/test'; + import { NavigationInstrumentation } from './instrumentation.ts'; import { ATTR_BROWSER_NAVIGATION_HASH_CHANGE, @@ -22,7 +24,6 @@ import { ATTR_URL_FULL, BROWSER_NAVIGATION_EVENT_NAME, } from './semconv.ts'; -import { defaultSanitizeUrl } from './utils.ts'; describe('NavigationInstrumentation', () => { let inMemoryExporter: InMemoryLogRecordExporter; diff --git a/packages/instrumentation/src/navigation/utils.test.ts b/packages/instrumentation/src/navigation/utils.test.ts index f8dd832..990930a 100644 --- a/packages/instrumentation/src/navigation/utils.test.ts +++ b/packages/instrumentation/src/navigation/utils.test.ts @@ -4,7 +4,8 @@ */ import { describe, expect, it } from 'vitest'; -import { defaultSanitizeUrl, isHashChange } from './utils.ts'; +import { defaultSanitizeUrl } from '#utils'; +import { isHashChange } from './utils.ts'; describe('isHashChange', () => { it('should return true when adding a hash to the same URL', () => { diff --git a/packages/instrumentation/src/navigation/utils.ts b/packages/instrumentation/src/navigation/utils.ts index 9d7ff79..f2549b5 100644 --- a/packages/instrumentation/src/navigation/utils.ts +++ b/packages/instrumentation/src/navigation/utils.ts @@ -3,67 +3,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -const SENSITIVE_PARAMS = [ - 'password', - 'passwd', - 'secret', - 'api_key', - 'apikey', - 'auth', - 'authorization', - 'token', - 'access_token', - 'refresh_token', - 'jwt', - 'session', - 'sessionid', - 'key', - 'private_key', - 'client_secret', - 'client_id', - 'signature', - 'hash', -]; - -/** - * Default URL sanitization function that redacts credentials and sensitive query parameters. - * This is the default implementation used when no custom sanitizeUrl callback is provided. - * - * @param url - The URL to sanitize - * @returns The sanitized URL with credentials and sensitive parameters redacted - */ -export function defaultSanitizeUrl(url: string): string { - try { - const urlObj = new URL(url); - - if (urlObj.username || urlObj.password) { - urlObj.username = 'REDACTED'; - urlObj.password = 'REDACTED'; - } - - for (const param of SENSITIVE_PARAMS) { - if (urlObj.searchParams.has(param)) { - urlObj.searchParams.set(param, 'REDACTED'); - } - } - - return urlObj.toString(); - } catch { - // If URL parsing fails, redact credentials and sensitive query parameters - // using regexes. The credential regex uses a restricted character class to - // avoid polynomial time complexity. - let sanitized = url.replace(/\/\/[^:/@]+:[^/@]+@/, '//REDACTED:REDACTED@'); - - for (const param of SENSITIVE_PARAMS) { - // Match param=value or param%3Dvalue (URL encoded) - const regex = new RegExp(`([?&]${param}(?:%3D|=))[^&]*`, 'gi'); - sanitized = sanitized.replace(regex, '$1REDACTED'); - } - - return sanitized; - } -} - /** * Determines if navigation between two URLs represents a hash change. * A hash change is true if the URLs are the same except for the hash part, diff --git a/packages/instrumentation/src/utils/index.ts b/packages/instrumentation/src/utils/index.ts index c925a48..0e4da19 100644 --- a/packages/instrumentation/src/utils/index.ts +++ b/packages/instrumentation/src/utils/index.ts @@ -5,3 +5,4 @@ export { getElementCSSSelector } from './getElementCSSSelector.ts'; export { getElementXPath } from './getElementXPath.ts'; +export { defaultSanitizeUrl } from './url.ts'; diff --git a/packages/instrumentation/src/utils/url.ts b/packages/instrumentation/src/utils/url.ts new file mode 100644 index 0000000..539759e --- /dev/null +++ b/packages/instrumentation/src/utils/url.ts @@ -0,0 +1,56 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +const SENSITIVE_PARAMS = [ + 'password', + 'passwd', + 'secret', + 'api_key', + 'apikey', + 'auth', + 'authorization', + 'token', + 'access_token', + 'refresh_token', + 'jwt', + 'session', + 'sessionid', + 'key', + 'private_key', + 'client_secret', + 'client_id', + 'signature', + 'hash', +]; + +/** + * Default URL sanitization function that redacts credentials and sensitive query parameters. + * This is the default implementation used when no custom sanitizeUrl callback is provided. + * + * @param url - The URL to sanitize + * @returns The sanitized URL with credentials and sensitive parameters redacted + */ +export function defaultSanitizeUrl(url: string): string { + try { + const urlObj = new URL(url); + if (urlObj.username || urlObj.password) { + urlObj.username = 'REDACTED'; + urlObj.password = 'REDACTED'; + } + for (const param of SENSITIVE_PARAMS) { + if (urlObj.searchParams.has(param)) { + urlObj.searchParams.set(param, 'REDACTED'); + } + } + return urlObj.toString(); + } catch { + let sanitized = url.replace(/\/\/[^:/@]+:[^/@]+@/, '//REDACTED:REDACTED@'); + for (const param of SENSITIVE_PARAMS) { + const regex = new RegExp(`([?&]${param}(?:%3D|=))[^&]*`, 'gi'); + sanitized = sanitized.replace(regex, '$1REDACTED'); + } + return sanitized; + } +}