Skip to content

Commit 8ccb82d

Browse files
Lms24lforst
andauthored
fix(node): Redact URL authority only in breadcrumbs and spans (#7740)
In #7667 we missed that our `urlToOptions` helper function is actually called to normalize request options that are then passed to the actual http client. Meaning, we shouldn't have redacted the authority in this function but at a later time when we extract the sanitized version (`extractUrl`). This PR changes the redaction location accordingly and hence fixes requests with authority not being sent properly. Co-authored-by: Luca Forstner <luca.forstner@sentry.io>
1 parent a0e9489 commit 8ccb82d

File tree

2 files changed

+18
-7
lines changed

2 files changed

+18
-7
lines changed

packages/node/src/integrations/utils/http.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,17 @@ export function extractUrl(requestOptions: RequestOptions): string {
4747
!requestOptions.port || requestOptions.port === 80 || requestOptions.port === 443 ? '' : `:${requestOptions.port}`;
4848
// do not include search or hash in span descriptions, per https://develop.sentry.dev/sdk/data-handling/#structuring-data
4949
const path = requestOptions.pathname || '/';
50-
const authority = requestOptions.auth ? `${requestOptions.auth}@` : '';
50+
// always filter authority, see https://develop.sentry.dev/sdk/data-handling/#structuring-data
51+
const authority = requestOptions.auth ? redactAuthority(requestOptions.auth) : '';
5152

5253
return `${protocol}//${authority}${hostname}${port}${path}`;
5354
}
5455

56+
function redactAuthority(auth: string): string {
57+
const [user, password] = auth.split(':');
58+
return `${user ? '[Filtered]' : ''}:${password ? '[Filtered]' : ''}@`;
59+
}
60+
5561
/**
5662
* Handle various edge cases in the span description (for spans representing http(s) requests).
5763
*
@@ -122,8 +128,7 @@ export function urlToOptions(url: URL): RequestOptions {
122128
options.port = Number(url.port);
123129
}
124130
if (url.username || url.password) {
125-
// always filter authority, see https://develop.sentry.dev/sdk/data-handling/#structuring-data
126-
options.auth = '[Filtered]:[Filtered]';
131+
options.auth = `${url.username}:${url.password}`;
127132
}
128133
return options;
129134
}

packages/node/test/integrations/http.test.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -214,18 +214,24 @@ describe('tracing', () => {
214214
expect(spans[1].data['http.fragment']).toEqual('learn-more');
215215
});
216216

217-
it('filters the authority (username and password) in span description', () => {
218-
nock('http://username:password@dogs.are.great').get('/').reply(200);
217+
it.each([
218+
['user:pwd', '[Filtered]:[Filtered]@'],
219+
['user:', '[Filtered]:@'],
220+
['user', '[Filtered]:@'],
221+
[':pwd', ':[Filtered]@'],
222+
['', ''],
223+
])('filters the authority %s in span description', (auth, redactedAuth) => {
224+
nock(`http://${auth}@dogs.are.great`).get('/').reply(200);
219225

220226
const transaction = createTransactionOnScope();
221227
const spans = (transaction as unknown as Span).spanRecorder?.spans as Span[];
222228

223-
http.get('http://username:password@dogs.are.great/');
229+
http.get(`http://${auth}@dogs.are.great/`);
224230

225231
expect(spans.length).toEqual(2);
226232

227233
// our span is at index 1 because the transaction itself is at index 0
228-
expect(spans[1].description).toEqual('GET http://[Filtered]:[Filtered]@dogs.are.great/');
234+
expect(spans[1].description).toEqual(`GET http://${redactedAuth}dogs.are.great/`);
229235
});
230236

231237
describe('Tracing options', () => {

0 commit comments

Comments
 (0)