Skip to content
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

[RUMF-1028] enable privacy by default #1049

Merged
merged 6 commits into from
Sep 21, 2021
Merged
Show file tree
Hide file tree
Changes from 5 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
17 changes: 7 additions & 10 deletions packages/core/src/domain/configuration/configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ import { catchUserErrors } from '../../tools/catchUserErrors'
import { includes, objectHasValue, ONE_KILO_BYTE, ONE_SECOND } from '../../tools/utils'
import { computeTransportConfiguration, TransportConfiguration } from './transportConfiguration'

export const InitialPrivacyLevel = {
export const DefaultPrivacyLevel = {
ALLOW: 'allow',
MASK: 'mask',
MASK_FORMS_ONLY: 'mask-forms-only',
MASK_USER_INPUT: 'mask-user-input',
amortemousque marked this conversation as resolved.
Show resolved Hide resolved
} as const
export type InitialPrivacyLevel = typeof InitialPrivacyLevel[keyof typeof InitialPrivacyLevel]
export type DefaultPrivacyLevel = typeof DefaultPrivacyLevel[keyof typeof DefaultPrivacyLevel]

export const DEFAULT_CONFIGURATION = {
allowedTracingOrigins: [] as Array<string | RegExp>,
Expand All @@ -20,7 +20,7 @@ export const DEFAULT_CONFIGURATION = {
silentMultipleInit: false,
trackInteractions: false,
trackViewsManually: false,
initialPrivacyLevel: InitialPrivacyLevel.ALLOW as InitialPrivacyLevel,
defaultPrivacyLevel: DefaultPrivacyLevel.MASK_USER_INPUT as DefaultPrivacyLevel,

/**
* arbitrary value, byte precision not needed
Expand Down Expand Up @@ -66,7 +66,7 @@ export interface InitConfiguration {
proxyHost?: string
proxyUrl?: string
beforeSend?: BeforeSendCallback
initialPrivacyLevel?: InitialPrivacyLevel
defaultPrivacyLevel?: DefaultPrivacyLevel

service?: string
env?: string
Expand Down Expand Up @@ -142,11 +142,8 @@ export function buildConfiguration(initConfiguration: InitConfiguration, buildEn
configuration.actionNameAttribute = initConfiguration.actionNameAttribute
}

if (
configuration.isEnabled('initial-privacy-level-option') &&
objectHasValue(InitialPrivacyLevel, initConfiguration.initialPrivacyLevel)
) {
configuration.initialPrivacyLevel = initConfiguration.initialPrivacyLevel
if (objectHasValue(DefaultPrivacyLevel, initConfiguration.defaultPrivacyLevel)) {
configuration.defaultPrivacyLevel = initConfiguration.defaultPrivacyLevel
}

return configuration
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/domain/configuration/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ export {
InitConfiguration,
buildCookieOptions,
BeforeSendCallback,
InitialPrivacyLevel,
DefaultPrivacyLevel,
buildConfiguration,
} from './configuration'
2 changes: 1 addition & 1 deletion packages/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ export {
InitConfiguration,
buildCookieOptions,
BeforeSendCallback,
InitialPrivacyLevel,
DefaultPrivacyLevel,
} from './domain/configuration'
export { trackConsoleError } from './domain/error/trackConsoleError'
export { trackRuntimeError } from './domain/error/trackRuntimeError'
Expand Down
31 changes: 10 additions & 21 deletions packages/rum-core/src/boot/rumPublicApi.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ONE_SECOND, RelativeTime, getTimeStamp, display, TimeStamp, InitialPrivacyLevel } from '@datadog/browser-core'
import { ONE_SECOND, RelativeTime, getTimeStamp, display, TimeStamp, DefaultPrivacyLevel } from '@datadog/browser-core'
import { noopRecorderApi, setup, TestSetupBuilder } from '../../test/specHelper'
import { ActionType } from '../rawRumEvent.types'
import { makeRumPublicApi, RumPublicApi, RumInitConfiguration, StartRum, RecorderApi } from './rumPublicApi'
Expand Down Expand Up @@ -668,30 +668,19 @@ describe('rum public api', () => {
setupBuilder.cleanup()
})

it('recording is started with the default initialPrivacyLevel', () => {
it('recording is started with the default defaultPrivacyLevel', () => {
rumPublicApi.init(DEFAULT_INIT_CONFIGURATION)
expect(recorderApiOnRumStartSpy.calls.mostRecent().args[2].initialPrivacyLevel).toBe(InitialPrivacyLevel.ALLOW)
})

describe('initial-privacy-level-option feature enabled', () => {
it('recording is started with the configured initialPrivacyLevel', () => {
rumPublicApi.init({
...DEFAULT_INIT_CONFIGURATION,
initialPrivacyLevel: InitialPrivacyLevel.MASK,
enableExperimentalFeatures: ['initial-privacy-level-option'],
})
expect(recorderApiOnRumStartSpy.calls.mostRecent().args[2].initialPrivacyLevel).toBe(InitialPrivacyLevel.MASK)
})
expect(recorderApiOnRumStartSpy.calls.mostRecent().args[2].defaultPrivacyLevel).toBe(
DefaultPrivacyLevel.MASK_USER_INPUT
)
})

describe('initial-privacy-level-option feature disabled', () => {
it('recording ignores the configured initialPrivacyLevel', () => {
rumPublicApi.init({
...DEFAULT_INIT_CONFIGURATION,
initialPrivacyLevel: InitialPrivacyLevel.MASK,
})
expect(recorderApiOnRumStartSpy.calls.mostRecent().args[2].initialPrivacyLevel).toBe(InitialPrivacyLevel.ALLOW)
it('recording is started with the configured defaultPrivacyLevel', () => {
rumPublicApi.init({
...DEFAULT_INIT_CONFIGURATION,
defaultPrivacyLevel: DefaultPrivacyLevel.MASK,
})
expect(recorderApiOnRumStartSpy.calls.mostRecent().args[2].defaultPrivacyLevel).toBe(DefaultPrivacyLevel.MASK)
})
})
})
4 changes: 2 additions & 2 deletions packages/rum-core/src/boot/rumPublicApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import {
InternalMonitoring,
callMonitored,
createHandlingStack,
InitialPrivacyLevel,
DefaultPrivacyLevel,
} from '@datadog/browser-core'
import { LifeCycle } from '../domain/lifeCycle'
import { ParentContexts } from '../domain/parentContexts'
Expand All @@ -32,7 +32,7 @@ import { startRum } from './startRum'
export interface RumInitConfiguration extends InitConfiguration {
applicationId: string
beforeSend?: (event: RumEvent, context: RumEventDomainContext) => void | boolean
initialPrivacyLevel?: InitialPrivacyLevel
defaultPrivacyLevel?: DefaultPrivacyLevel
}

export type RumPublicApi = ReturnType<typeof makeRumPublicApi>
Expand Down
2 changes: 1 addition & 1 deletion packages/rum-slim/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,4 @@ export {
RumOtherResourceEventDomainContext,
RumLongTaskEventDomainContext,
} from '@datadog/browser-rum-core'
export { InitialPrivacyLevel } from '@datadog/browser-core'
export { DefaultPrivacyLevel } from '@datadog/browser-core'
5 changes: 4 additions & 1 deletion packages/rum/src/boot/startRecording.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { HttpRequest } from '@datadog/browser-core'
import { HttpRequest, DefaultPrivacyLevel } from '@datadog/browser-core'
import { LifeCycle, LifeCycleEventType } from '@datadog/browser-rum-core'
import { inflate } from 'pako'
import { createRumSessionMock, RumSessionMock } from '../../../rum-core/test/mockRumSession'
Expand Down Expand Up @@ -52,6 +52,9 @@ describe('startRecording', () => {
},
})
.withSession(session)
.withConfiguration({
defaultPrivacyLevel: DefaultPrivacyLevel.ALLOW,
})
.beforeBuild(({ lifeCycle, applicationId, configuration, parentContexts, session }) => {
;({ stop: stopRecording } = startRecording(lifeCycle, applicationId, configuration, session, parentContexts))
return { stop: stopRecording }
Expand Down
2 changes: 1 addition & 1 deletion packages/rum/src/boot/startRecording.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export function startRecording(

const { stop: stopRecording, takeFullSnapshot, flushMutations } = record({
emit: addRawRecord,
initialPrivacyLevel: configuration.initialPrivacyLevel,
defaultPrivacyLevel: configuration.defaultPrivacyLevel,
})

const { unsubscribe: unsubscribeViewEnded } = lifeCycle.subscribe(LifeCycleEventType.VIEW_ENDED, () => {
Expand Down
16 changes: 8 additions & 8 deletions packages/rum/src/constants.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { InitialPrivacyLevel } from '@datadog/browser-core'
import { DefaultPrivacyLevel } from '@datadog/browser-core'

export const NodePrivacyLevel = {
...InitialPrivacyLevel,
...DefaultPrivacyLevel,
IGNORE: 'ignore',
HIDDEN: 'hidden',
} as const
Expand All @@ -10,21 +10,21 @@ export type NodePrivacyLevel = typeof NodePrivacyLevel[keyof typeof NodePrivacyL
export const PRIVACY_ATTR_NAME = 'data-dd-privacy'

// Deprecate via temporary Alias
export const PRIVACY_CLASS_INPUT_IGNORED = 'dd-privacy-input-ignored' // DEPRECATED, aliased to mask-forms-only
export const PRIVACY_CLASS_INPUT_MASKED = 'dd-privacy-input-masked' // DEPRECATED, aliased to mask-forms-only
export const PRIVACY_ATTR_VALUE_INPUT_IGNORED = 'input-ignored' // DEPRECATED, aliased to mask-forms-only
export const PRIVACY_ATTR_VALUE_INPUT_MASKED = 'input-masked' // DEPRECATED, aliased to mask-forms-only
export const PRIVACY_CLASS_INPUT_IGNORED = 'dd-privacy-input-ignored' // DEPRECATED, aliased to mask-user-input
export const PRIVACY_CLASS_INPUT_MASKED = 'dd-privacy-input-masked' // DEPRECATED, aliased to mask-user-input
export const PRIVACY_ATTR_VALUE_INPUT_IGNORED = 'input-ignored' // DEPRECATED, aliased to mask-user-input
export const PRIVACY_ATTR_VALUE_INPUT_MASKED = 'input-masked' // DEPRECATED, aliased to mask-user-input

// Privacy Attrs
export const PRIVACY_ATTR_VALUE_ALLOW = 'allow'
export const PRIVACY_ATTR_VALUE_MASK = 'mask'
export const PRIVACY_ATTR_VALUE_MASK_FORMS_ONLY = 'mask-forms-only'
export const PRIVACY_ATTR_VALUE_MASK_USER_INPUT = 'mask-user-input'
export const PRIVACY_ATTR_VALUE_HIDDEN = 'hidden'

// Privacy Classes - not all customers can set plain HTML attributes, so support classes too
export const PRIVACY_CLASS_ALLOW = 'dd-privacy-allow'
export const PRIVACY_CLASS_MASK = 'dd-privacy-mask'
export const PRIVACY_CLASS_MASK_FORMS_ONLY = 'dd-privacy-mask-forms-only'
export const PRIVACY_CLASS_MASK_USER_INPUT = 'dd-privacy-mask-user-input'
export const PRIVACY_CLASS_HIDDEN = 'dd-privacy-hidden'

// Private Replacement Templates
Expand Down
28 changes: 14 additions & 14 deletions packages/rum/src/domain/record/mutationObserver.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { InitialPrivacyLevel } from '@datadog/browser-core'
import { DefaultPrivacyLevel } from '@datadog/browser-core'
import { isIE } from '../../../../core/test/specHelper'
import { collectAsyncCalls, createMutationPayloadValidator } from '../../../test/utils'
import {
Expand All @@ -8,7 +8,7 @@ import {
PRIVACY_ATTR_VALUE_INPUT_IGNORED,
PRIVACY_ATTR_VALUE_INPUT_MASKED,
PRIVACY_ATTR_VALUE_MASK,
PRIVACY_ATTR_VALUE_MASK_FORMS_ONLY,
PRIVACY_ATTR_VALUE_MASK_USER_INPUT,
} from '../../constants'
import { serializeDocument } from './serialize'
import { sortAddedAndMovedNodes, startMutationObserver, MutationController } from './mutationObserver'
Expand All @@ -18,14 +18,14 @@ describe('startMutationCollection', () => {
let sandbox: HTMLElement
let stopMutationCollection: () => void

function startMutationCollection(initialPrivacyLevel: InitialPrivacyLevel = InitialPrivacyLevel.ALLOW) {
function startMutationCollection(defaultPrivacyLevel: DefaultPrivacyLevel = DefaultPrivacyLevel.ALLOW) {
const mutationCallbackSpy = jasmine.createSpy<MutationCallBack>()
const mutationController = new MutationController()

;({ stop: stopMutationCollection } = startMutationObserver(
mutationController,
mutationCallbackSpy,
initialPrivacyLevel
defaultPrivacyLevel
))

return {
Expand Down Expand Up @@ -401,9 +401,9 @@ describe('startMutationCollection', () => {
})
})

it('respects the initial privacy level setting', () => {
it('respects the default privacy level setting', () => {
const serializedDocument = serializeDocument(document, NodePrivacyLevel.ALLOW)
const { mutationController, getLatestMutationPayload } = startMutationCollection(InitialPrivacyLevel.MASK)
const { mutationController, getLatestMutationPayload } = startMutationCollection(DefaultPrivacyLevel.MASK)

sandbox.innerText = 'foo bar'
mutationController.flush()
Expand Down Expand Up @@ -462,9 +462,9 @@ describe('startMutationCollection', () => {
expect(mutationCallbackSpy).not.toHaveBeenCalled()
})

it('respects the initial privacy level setting', () => {
it('respects the default privacy level setting', () => {
const serializedDocument = serializeDocument(document, NodePrivacyLevel.ALLOW)
const { mutationController, getLatestMutationPayload } = startMutationCollection(InitialPrivacyLevel.MASK)
const { mutationController, getLatestMutationPayload } = startMutationCollection(DefaultPrivacyLevel.MASK)

textNode.data = 'foo bar'
mutationController.flush()
Expand All @@ -491,7 +491,7 @@ describe('startMutationCollection', () => {

const serializedDocument = serializeDocument(document, NodePrivacyLevel.MASK)
const { mutationController, mutationCallbackSpy, getLatestMutationPayload } = startMutationCollection(
InitialPrivacyLevel.MASK
DefaultPrivacyLevel.MASK
)

div.firstChild!.textContent = 'bazz 7'
Expand Down Expand Up @@ -563,9 +563,9 @@ describe('startMutationCollection', () => {
})
})

it('respects the initial privacy level setting', () => {
it('respects the default privacy level setting', () => {
const serializedDocument = serializeDocument(document, NodePrivacyLevel.ALLOW)
const { mutationController, getLatestMutationPayload } = startMutationCollection(InitialPrivacyLevel.MASK)
const { mutationController, getLatestMutationPayload } = startMutationCollection(DefaultPrivacyLevel.MASK)

sandbox.setAttribute('data-foo', 'biz')
mutationController.flush()
Expand Down Expand Up @@ -812,10 +812,10 @@ describe('startMutationCollection', () => {
expectedAttributesMutation: { value: '***' },
},
{
privacyAttributeValue: PRIVACY_ATTR_VALUE_MASK_FORMS_ONLY,
privacyAttributeValue: PRIVACY_ATTR_VALUE_MASK_USER_INPUT,
privacyAttributeOn: 'input',
expectedSerializedAttributes: {
[PRIVACY_ATTR_NAME]: PRIVACY_ATTR_VALUE_MASK_FORMS_ONLY,
[PRIVACY_ATTR_NAME]: PRIVACY_ATTR_VALUE_MASK_USER_INPUT,
value: '***',
},
expectedAttributesMutation: { value: '***' },
Expand Down Expand Up @@ -848,7 +848,7 @@ describe('startMutationCollection', () => {
expectedAttributesMutation: { value: '***' },
},
{
privacyAttributeValue: PRIVACY_ATTR_VALUE_MASK_FORMS_ONLY,
privacyAttributeValue: PRIVACY_ATTR_VALUE_MASK_USER_INPUT,
privacyAttributeOn: 'ancestor',
expectedSerializedAttributes: { value: '***' },
expectedAttributesMutation: { value: '***' },
Expand Down
Loading