Skip to content

Commit

Permalink
feat: scrub sensitive data from Sentry requests
Browse files Browse the repository at this point in the history
  • Loading branch information
jorilindell committed Jun 21, 2024
1 parent 6f5fe53 commit 71e8217
Show file tree
Hide file tree
Showing 6 changed files with 149 additions and 2 deletions.
8 changes: 8 additions & 0 deletions sentry.client.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,16 @@
// https://docs.sentry.io/platforms/javascript/guides/nextjs/

import * as Sentry from '@sentry/nextjs';

import {
beforeSend,
beforeSendTransaction,
} from './src/domain/app/sentry/utils';

if (process.env.NODE_ENV === 'production') {
Sentry.init({
beforeSend,
beforeSendTransaction,
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
environment: process.env.NEXT_PUBLIC_ENVIRONMENT,
ignoreErrors: [
Expand Down
8 changes: 8 additions & 0 deletions sentry.edge.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,16 @@
// https://docs.sentry.io/platforms/javascript/guides/nextjs/

import * as Sentry from '@sentry/nextjs';

import {
beforeSend,
beforeSendTransaction,
} from './src/domain/app/sentry/utils';

if (process.env.NODE_ENV === 'production') {
Sentry.init({
beforeSend,
beforeSendTransaction,
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
environment: process.env.NEXT_PUBLIC_ENVIRONMENT,

Expand Down
7 changes: 7 additions & 0 deletions sentry.server.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,15 @@

import * as Sentry from '@sentry/nextjs';

import {
beforeSend,
beforeSendTransaction,
} from './src/domain/app/sentry/utils';

if (process.env.NODE_ENV === 'production') {
Sentry.init({
beforeSend,
beforeSendTransaction,
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
environment: process.env.NEXT_PUBLIC_ENVIRONMENT,

Expand Down
68 changes: 68 additions & 0 deletions src/domain/app/sentry/__test__/utils.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import {
beforeSend,
beforeSendTransaction,
cleanSensitiveData,
} from '../utils';

const sensitive = 'sensitive';
const safe = 'safe';

const originalData = {
a: safe,
access_code: sensitive,
accessCode: sensitive,
city: sensitive,
date_of_birth: sensitive,
email: sensitive,
extra_info: sensitive,
first_name: sensitive,
last_name: sensitive,
membership_number: sensitive,
native_language: sensitive,
phone_number: sensitive,
postal_code: sensitive,
service_language: sensitive,
street_address: sensitive,
user_email: sensitive,
user_name: sensitive,
user_phone_number: sensitive,
zipcode: sensitive,
arrayOfObjects: [
{ a: safe, accessCode: sensitive },
{ b: safe, accessCode: sensitive },
],
arrayOfStrings: [safe],
object: { c: safe, userEmail: sensitive, userName: sensitive },
};

const cleanedData = {
a: safe,
arrayOfObjects: [{ a: safe }, { b: safe }],
arrayOfStrings: [safe],
object: { c: safe },
};

describe('beforeSend', () => {
it('should clear sensitive data', () => {
expect(
beforeSend({ extra: { data: originalData }, type: undefined })
).toEqual({ extra: { data: cleanedData } });
});
});

describe('beforeSendTransaction', () => {
it('should clear sensitive data', () => {
expect(
beforeSendTransaction({
extra: { data: originalData },
type: 'transaction',
})
).toEqual({ extra: { data: cleanedData }, type: 'transaction' });
});
});

describe('cleanSensitiveData', () => {
it('should clear sensitive data', () => {
expect(cleanSensitiveData(originalData)).toEqual(cleanedData);
});
});
56 changes: 56 additions & 0 deletions src/domain/app/sentry/utils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,60 @@
import * as Sentry from '@sentry/browser';
import { ErrorEvent, TransactionEvent } from '@sentry/types';
import isObject from 'lodash/isObject';
import snakeCase from 'lodash/snakeCase';

const SENTRY_DENYLIST = [
'access_code',
'city',
'date_of_birth',
'email',
'extra_info',
'first_name',
'last_name',
'membership_number',
'native_language',
'phone_number',
'postal_code',
'service_language',
'street_address',
'user_email',
'user_name',
'user_phone_number',
'zipcode',
];

export const cleanSensitiveData = (data: Record<string, unknown>) => {
Object.entries(data).forEach(([key, value]) => {
if (
SENTRY_DENYLIST.includes(key) ||
SENTRY_DENYLIST.includes(snakeCase(key))
) {
delete data[key];
} else if (isObject(value)) {
data[key] = cleanSensitiveData(value as Record<string, unknown>);
} else if (Array.isArray(value)) {
data[key] = value.map((item) =>
isObject(item)
? cleanSensitiveData(item as Record<string, unknown>)
: item
);
}
});

return data;
};

export const beforeSend = (event: ErrorEvent): ErrorEvent =>
cleanSensitiveData(
event as unknown as Record<string, unknown>
) as unknown as ErrorEvent;

export const beforeSendTransaction = (
event: TransactionEvent
): TransactionEvent =>
cleanSensitiveData(
event as unknown as Record<string, unknown>
) as unknown as TransactionEvent;

const reportError = ({
data,
Expand Down
4 changes: 2 additions & 2 deletions src/hooks/useHandleError.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { reportError } from '../domain/app/sentry/utils';
import { cleanSensitiveData, reportError } from '../domain/app/sentry/utils';
import useUser from '../domain/user/hooks/useUser';
import { MutationCallbacks } from '../types';

Expand Down Expand Up @@ -49,7 +49,7 @@ function useHandleError<PayloadType, ObjectType>(): UseHandleErrorState<
reportError({
data: {
error,
payloadAsString: payload && JSON.stringify(payload),
payloadAsString: payload && JSON.stringify(cleanSensitiveData(payload)),
object,
user: user?.username,
},
Expand Down

0 comments on commit 71e8217

Please sign in to comment.