Skip to content

fix(core): Add sentry_client to auth headers #5413

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jul 14, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/browser/src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ export class BrowserClient extends BaseClient<BrowserClientOptions> {

__DEBUG_BUILD__ && logger.log('Sending outcomes:', outcomes);

const url = getEnvelopeEndpointWithUrlEncodedAuth(this._dsn, this._options.tunnel);
const url = getEnvelopeEndpointWithUrlEncodedAuth(this._dsn, this._options);
const envelope = createClientReportEnvelope(outcomes, this._options.tunnel && dsnToString(this._dsn));

try {
Expand Down
22 changes: 18 additions & 4 deletions packages/core/src/api.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { DsnComponents, DsnLike } from '@sentry/types';
import { ClientOptions, DsnComponents, DsnLike, SdkInfo } from '@sentry/types';
import { dsnToString, makeDsn, urlEncode } from '@sentry/utils';

const SENTRY_API_VERSION = '7';
Expand All @@ -16,12 +16,13 @@ function _getIngestEndpoint(dsn: DsnComponents): string {
}

/** Returns a URL-encoded string with auth config suitable for a query string. */
function _encodedAuth(dsn: DsnComponents): string {
function _encodedAuth(dsn: DsnComponents, sdkInfo: SdkInfo | undefined): string {
return urlEncode({
// We send only the minimum set of required information. See
// https://github.com/getsentry/sentry-javascript/issues/2572.
sentry_key: dsn.publicKey,
sentry_version: SENTRY_API_VERSION,
...(sdkInfo && { sentry_client: `${sdkInfo.name}/${sdkInfo.version}` }),
});
}

Expand All @@ -30,8 +31,21 @@ function _encodedAuth(dsn: DsnComponents): string {
*
* Sending auth as part of the query string and not as custom HTTP headers avoids CORS preflight requests.
*/
export function getEnvelopeEndpointWithUrlEncodedAuth(dsn: DsnComponents, tunnel?: string): string {
return tunnel ? tunnel : `${_getIngestEndpoint(dsn)}?${_encodedAuth(dsn)}`;
export function getEnvelopeEndpointWithUrlEncodedAuth(
dsn: DsnComponents,
// TODO (v8): Remove `tunnelOrOptions` in favor of `options`, and use the substitute code below
// options: ClientOptions = {} as ClientOptions,
tunnelOrOptions: string | ClientOptions = {} as ClientOptions,
): string {
// TODO (v8): Use this code instead
// const { tunnel, _metadata = {} } = options;
// return tunnel ? tunnel : `${_getIngestEndpoint(dsn)}?${_encodedAuth(dsn, _metadata.sdk)}`;

const tunnel = typeof tunnelOrOptions === 'string' ? tunnelOrOptions : tunnelOrOptions.tunnel;
const sdkInfo =
typeof tunnelOrOptions === 'string' || !tunnelOrOptions._metadata ? undefined : tunnelOrOptions._metadata.sdk;

return tunnel ? tunnel : `${_getIngestEndpoint(dsn)}?${_encodedAuth(dsn, sdkInfo)}`;
}

/** Returns the url to the report dialog endpoint. */
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/baseclient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ export abstract class BaseClient<O extends ClientOptions> implements Client<O> {
this._options = options;
if (options.dsn) {
this._dsn = makeDsn(options.dsn);
const url = getEnvelopeEndpointWithUrlEncodedAuth(this._dsn, options.tunnel);
const url = getEnvelopeEndpointWithUrlEncodedAuth(this._dsn, options);
this._transport = options.transport({
recordDroppedEvent: this.recordDroppedEvent.bind(this),
...options.transportOptions,
Expand Down
43 changes: 39 additions & 4 deletions packages/core/test/lib/api.test.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,55 @@
/* eslint-disable deprecation/deprecation */
import { ClientOptions, DsnComponents } from '@sentry/types';
import { makeDsn } from '@sentry/utils';

import { getEnvelopeEndpointWithUrlEncodedAuth, getReportDialogEndpoint } from '../../src/api';

const ingestDsn = 'https://[email protected]:1234/subpath/123';
const dsnPublic = 'https://[email protected]:1234/subpath/123';
const tunnel = 'https://hello.com/world';
const _metadata = { sdk: { name: 'sentry.javascript.browser', version: '12.31.12' } } as ClientOptions['_metadata'];

const dsnPublicComponents = makeDsn(dsnPublic);

describe('API', () => {
test('getEnvelopeEndpoint', () => {
expect(getEnvelopeEndpointWithUrlEncodedAuth(dsnPublicComponents)).toEqual(
'https://sentry.io:1234/subpath/api/123/envelope/?sentry_key=abc&sentry_version=7',
describe('getEnvelopeEndpointWithUrlEncodedAuth', () => {
it.each([
[
"doesn't include `sentry_client` when called with only DSN",
dsnPublicComponents,
undefined,
'https://sentry.io:1234/subpath/api/123/envelope/?sentry_key=abc&sentry_version=7',
],
['uses `tunnel` value when called with `tunnel` as string', dsnPublicComponents, tunnel, tunnel],
[
'uses `tunnel` value when called with `tunnel` in options',
dsnPublicComponents,
{ tunnel } as ClientOptions,
tunnel,
],
[
'uses `tunnel` value when called with `tunnel` and `_metadata` in options',
dsnPublicComponents,
{ tunnel, _metadata } as ClientOptions,
tunnel,
],
[
'includes `sentry_client` when called with `_metadata` in options and no tunnel',
dsnPublicComponents,
{ _metadata } as ClientOptions,
'https://sentry.io:1234/subpath/api/123/envelope/?sentry_key=abc&sentry_version=7&sentry_client=sentry.javascript.browser%2F12.31.12',
],
])(
'%s',
(
_testName: string,
dsnComponents: DsnComponents,
tunnelOrOptions: string | ClientOptions | undefined,
expected: string,
) => {
expect(getEnvelopeEndpointWithUrlEncodedAuth(dsnComponents, tunnelOrOptions)).toBe(expected);
},
);
expect(getEnvelopeEndpointWithUrlEncodedAuth(dsnPublicComponents, tunnel)).toEqual(tunnel);
});

describe('getReportDialogEndpoint', () => {
Expand Down