Skip to content

Commit

Permalink
[RUMF-1028] enable privacy by default (#1049)
Browse files Browse the repository at this point in the history
* [RUMF-1028] change initialPrivacyLevel default to MASK_FORMS_ONLY

* [RUMF-1028] remove initial-privacy-level-option flag

* ✅ [RUMF-1028] fix E2E tests

* rename initialPrivacyLevel to defaultPrivacyLevel

* rename mask-forms-only to mask-user-input
  • Loading branch information
BenoitZugmeyer authored Sep 21, 2021
1 parent af779fc commit 2880e6b
Show file tree
Hide file tree
Showing 23 changed files with 156 additions and 162 deletions.
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',
} 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 @@ -21,7 +21,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 @@ -67,7 +67,7 @@ export interface InitConfiguration {
proxyHost?: string
proxyUrl?: string
beforeSend?: BeforeSendCallback
initialPrivacyLevel?: InitialPrivacyLevel
defaultPrivacyLevel?: DefaultPrivacyLevel

service?: string
env?: string
Expand Down Expand Up @@ -143,11 +143,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

0 comments on commit 2880e6b

Please sign in to comment.