-
Notifications
You must be signed in to change notification settings - Fork 128
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
✨ [RUM-3902] Add privacy control for action names #2707
base: main
Are you sure you want to change the base?
Conversation
packages/rum-core/src/domain/action/getActionNameFromElement.ts
Outdated
Show resolved
Hide resolved
packages/rum-core/src/domain/action/getActionNameFromElement.ts
Outdated
Show resolved
Hide resolved
selector: getSelectorFromElement(event.target, actionNameAttribute), | ||
}, | ||
target: | ||
actionName === ACTION_NAME_PLACEHOLDER && privacyEnabledForActionName ? assign({ masked: true }, target) : target, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💭 thought: This check actionName === ACTION_NAME_PLACEHOLDER
makes me wondering if the privacy logic could not be collocated to the action name computation. Something like
function getActionNameFromElement(element: Element, configuration: RumConfiguration): { value: string, masked: boolean }
Bundles Sizes Evolution
🚀 CPU Performance
🧠 Memory Performance
|
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #2707 +/- ##
=======================================
Coverage 93.26% 93.27%
=======================================
Files 241 240 -1
Lines 7028 7051 +23
Branches 1553 1564 +11
=======================================
+ Hits 6555 6577 +22
- Misses 473 474 +1 ☔ View full report in Codecov by Sentry. |
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as duplicate.
This comment was marked as duplicate.
…n-name into staging-17 Co-authored-by: cy-moi <congyao119@gmail.com>
This comment was marked as outdated.
This comment was marked as outdated.
// When the node is set to hidden, we do not track click action | ||
// Make sure everything has been done before return | ||
if (privacyLevel === NodePrivacyLevel.HIDDEN && configuration.enablePrivacyForActionName) { | ||
return | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💬 suggestion: I think this condition could be done earlier in processPointerDown
. The privacy level could be passed to computeClickActionBase
. This way no need for this check:
if (clickActionBase) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I moved it to processPointerDown
but I do not see how we could get rid of the check of clickActionBase
because if would still be undefined when we skip hidden
override.
Edit: should be fixed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about action names relying on innerText (cf Privacy control options for action names RFC)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This logic should be added when there are html privacy overriding attributes.
f5fd1a2
to
18eaec5
Compare
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
packages/rum-core/src/domain/action/getActionNameFromElement.ts
Outdated
Show resolved
Hide resolved
@@ -201,6 +246,11 @@ function getTextualContent(element: Element | HTMLElement, userProgrammaticAttri | |||
removeTextFromElements(`[${userProgrammaticAttribute}]`) | |||
} | |||
|
|||
if (privacyEnabledActionName) { | |||
// remove the text of elements with privacy override | |||
removeTextFromElements(`[${PRIVACY_ATTR_NAME}=${NodePrivacyLevel.MASK}]`) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💬 suggestion: We probably want the same treatment for "mask" | "hidden" and "mask-user-input".
Also customers can use class name to define privacy level. cf doc
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should mask-user-input
not be masked when it is not an input area?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes in fact there is nothing to do for "mask-user-input" has the name does not take into account input value
packages/rum-core/src/domain/action/getActionNameFromElement.ts
Outdated
Show resolved
Hide resolved
packages/rum-core/src/domain/action/getActionNameFromElement.ts
Outdated
Show resolved
Hide resolved
packages/rum-core/src/domain/action/getActionNameFromElement.spec.ts
Outdated
Show resolved
Hide resolved
const nodePrivacyLevel = getNodePrivacyLevel(pointerDownEvent.target, configuration.defaultPrivacyLevel) | ||
|
||
// When the node is set to hidden, we do not track click action | ||
// Make sure everything has been done before return | ||
if (nodePrivacyLevel === NodePrivacyLevel.HIDDEN && configuration.enablePrivacyForActionName) { | ||
return undefined | ||
} | ||
const privacyEnabledForActionName = | ||
nodePrivacyLevel === NodePrivacyLevel.MASK && configuration.enablePrivacyForActionName | ||
|
||
const clickActionBase = computeClickActionBase( | ||
pointerDownEvent, | ||
privacyEnabledForActionName, | ||
configuration.actionNameAttribute | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion 1: Don't compute nodePrivacyLevel
if enablePrivacyForActionName
is false
. Not only it will improve performance, it will also be easier to understand the code
Suggestion 2: pass nodePrivacyLevel
to computeClickActionBase
so we don't have to re-compute it there
let nodePrivacyLevel: NodePrivacyLevel
if (configuration.enablePrivacyForActionName) {
nodePrivacyLevel = getNodePrivacyLevel(pointerDownEvent.target, configuration.defaultPrivacyLevel)
// When the node is set to hidden, we do not track click action
// Make sure everything has been done before return
if (nodePrivacyLevel === NodePrivacyLevel.HIDDEN) {
return undefined
}
} else {
nodePrivacyLevel = NodePrivacyLevel.ALLOW
}
const clickActionBase = computeClickActionBase(
pointerDownEvent,
nodePrivacyLevel,
configuration.actionNameAttribute
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💬 suggestion: Maybe even simpler ;)
const nodePrivacyLevel = configuration.enablePrivacyForActionName
? getNodePrivacyLevel(pointerDownEvent.target, configuration.defaultPrivacyLevel)
: NodePrivacyLevel.ALLOW
if (nodePrivacyLevel === NodePrivacyLevel.HIDDEN) {
return undefined
}
const clickActionBase = computeClickActionBase(
pointerDownEvent,
nodePrivacyLevel,
configuration.actionNameAttribute
)
packages/rum-core/src/domain/action/getActionNameFromElement.ts
Outdated
Show resolved
Hide resolved
packages/rum-core/src/domain/action/getActionNameFromElement.ts
Outdated
Show resolved
Hide resolved
packages/rum-core/src/constants.ts
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💬 suggestion: The file name "constants.ts" is too generic. All constants in that file are related to privacy. Maybe it could merged into the "privacy.ts"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point. I merged it in privacy.ts
.
removeTextFromElements( | ||
`[${PRIVACY_ATTR_NAME}=${NodePrivacyLevel.MASK}], | ||
[${PRIVACY_ATTR_NAME}=${NodePrivacyLevel.HIDDEN}], | ||
[class=${PRIVACY_CLASS_MASK}], | ||
[class=${PRIVACY_CLASS_HIDDEN}]` | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💬 suggestion: I think we could extract the logic of having to check both the class and the attribute. Something like:
removeTextFromElements(
getPrivacySelector(NodePrivacyLevel.MASK),
getPrivacySelector(NodePrivacyLevel.HIDDEN)
)
It could even be used in getNodeSelfPrivacyLevel
// instead of
const privAttr = node.getAttribute(PRIVACY_ATTR_NAME)
if (privAttr === PRIVACY_ATTR_VALUE_MASK || elementClasslistContains(node, PRIVACY_CLASS_MASK))
// we could use
if(node.matches(getPrivacySelector(NodePrivacyLevel.MASK))
@BenoitZugmeyer do you see any downside of using matches, maybe the perf?
@@ -39,6 +39,7 @@ export interface RumInitConfiguration extends InitConfiguration { | |||
startSessionReplayRecordingManually?: boolean | undefined | |||
|
|||
// action options | |||
enablePrivacyForActionName?: boolean | undefined |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💬 suggestion: Could be nice to add a comment saying // TODO next major: remove this option and make privacy for action name the default behaviour
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
…n-name into staging-20 Co-authored-by: cy-moi <congyao119@gmail.com>
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
Commit 82036b1ee4 had already been merged into staging-21 If you need support, contact us on Slack #devflow! |
Motivation
To be consistent with session Replay and ease the customer configuration, we could use the same privacy options as Replay. To avoid breaking changes, we need to add an extra init option that indicates the action names should take into account the defaultPrivacyLevel and the HTML overrides.
Desired behavior
When the user opt-in for
enablePrivacyForActionName
, we mask action names when no action name attributes given and no html override.When the user does not opt-in for this feature, we mask action names when html override is set.
Changes
Add an opt-in field
enablePrivacyForActionName: boolean
in configuration. OnceenablePrivacyForActionName: true
, the action name computation would behave (taking into account of all privacy configs) as follow:This also works for html override
data-dd-privacy
accordingly.Testing
I have gone over the contributing documentation.