-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
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
text masking settings apply to inputs #1097
base: master
Are you sure you want to change the base?
Conversation
eae89e8
to
c4980bc
Compare
c4980bc
to
96fb991
Compare
if (classMatchesRegex(el, maskTextClass, true)) return true; | ||
} | ||
const maskDistance = distanceToMatch(el, maskTextClass, maskTextSelector); | ||
const unmaskDistance = distanceToMatch( |
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 think skipping this calculation when maskAllText
is false could improve the performance.
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.
updated this so that if maskAllText is true, and unmasking either is not configured (best case) or fails to find a match (worst case), then the masking distance is not computed.
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.
According to the documentation unmaskTextClass also works on conventional masking techniques. Maybe we need to check if a mask is applied first, before we check its unmask distance
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 added a branch for when maskAllText is false where masking is checked first, and then unmasking is checked only if masking applies to the element. The opposite happens when maskAllText is true, which addresses @YunFeng0817 's original comment.
Hi @mdellanoce, thanks for creating this Pull Request, I think this is a great idea to help give people more privacy and this should definitely be included in rrweb. I did notice one potential issue with this implementation: the Thanks again for submitting this, I think if we can get this performant this would be a great addition to rrweb! |
@Mark-Fenng @Juice10 thanks for the feedback, totally understand the performance concerns. I think the maskAllText suggestion will work, and I have a few other ideas. I'll see what I can do and hopefully ping you back in a few days. |
🦋 Changeset detectedLatest commit: b1a1922 The changes in this PR will be included in the next version bump. This PR includes changesets to release 8 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
ac3ea6e
to
69e5fb3
Compare
69e5fb3
to
0f6a611
Compare
@YunFeng0817 @Juice10 sorry for the delay, but I added 3 commits to address performance:
Hope that all makes sense. Let me know what you think. |
attributes.value = maskInputValue({ | ||
type: attributes.type, | ||
tagName, | ||
value, | ||
maskInputOptions, | ||
maskInputFn, | ||
forceMask, |
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.
Does this mean that maskAllText
will also mask inputs? Do we need (un)maskInput(Selector|Class)
as well so they can be selectively (un)masked?
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.
the masking and unmasking options in general apply to inputs, including maskAllText. So I was thinking unmaskSelector/Class already cover this.
the forceMask parameter is a little awkward, maybe there's a better way to do that. I'm evaluating the masking/unmasking settings outside of this function call to get a true/false value to pass to forceMask.
0f6a611
to
cc38118
Compare
@mdellanoce This PR is coming along really nicely. Since performance is such an important part of this it probably makes sense to re-run the benchmarks, and make some benchmarks of our own to understand the performance of this. |
39c1af0
to
79e113e
Compare
@Juice10 I added 2 new benchmarks for masking and unmasking. Here are the results from master: Note: the unmasking test on master is effectively the same as the masking test, since unmasking is unsupported there. Here are the results from my branch:
|
3b7ded7
to
32b726b
Compare
@Juice10 ready for another look, i think |
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.
@mdellanoce I meant to make these PR's to your fork, but I updated my local branches with master and it's causing bad diffs, so I'll just link the PRs from my fork -- if you update your branch with rrweb master, I can send out PRs
-
fix tests with maskAllText, add textarea to mask-text.html getsentry/rrweb#97 -- This fixes tests not properly using
maskAllText
, this shows that unmasking does not work. I've also added<textarea>
inmask-text.html
, as it has atextContent
prop that can conflict with itsvalue
attribute when masking. -
Add test for dynamically added inputs getsentry/rrweb#98 - adds additional tests for dynamically added inputs and different configurations of maskAllInput.
There are additional comments within these PRs that point out the failing/desired test results.
Let me know if you have any questions and if I can assist in any way!
@@ -597,6 +597,7 @@ export function generateRecordSnippet(options: recordOptions<eventWithTime>) { | |||
maskTextSelector: ${JSON.stringify(options.maskTextSelector)}, | |||
maskAllInputs: ${options.maskAllInputs}, | |||
maskInputOptions: ${JSON.stringify(options.maskAllInputs)}, | |||
maskInputFn: ${options.maskInputFn}, |
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.
You're not passing maskAllText
here so it's not being tested at all. e.g. add a <div>
with text content as a direct child of <body>
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.
fixed. also looks like the unmasking issue was the same (not passing unmaskTextSelector here), so I updated that as well. The test snapshots look correct to me now, but would definitely appreciate your eyes on them as well.
5ffcb9f
to
afec5a2
Compare
@billyvg i synced the branch with master, i'm looking into the unmasking issue you pointed out |
2f726fb
to
0bccb5b
Compare
\\"childNodes\\": [ | ||
{ | ||
\\"type\\": 3, | ||
\\"textContent\\": \\"*******\\\\n \\", |
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 this be unmasked since it has rr-unmask
class?
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 don't think so. one of the later commits makes unmaskTextClass empty by default, so since i didn't specify it in the test, this shouldn't be unmasked. I could remove the rr-unmask from the test file though, since I can see how that is confusing.
\\"childNodes\\": [ | ||
{ | ||
\\"type\\": 3, | ||
\\"textContent\\": \\"unmask2\\", |
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.
Looks correct, parent has [data-masking="false"]
|
Ah I see, that makes sense then, i was purely going from what I saw in the test snapshots (the snapshots make the tests hard to reason about). Documenting the masking precedence would definitely be helpful! |
Yeah, that's what is happening here too, as far as I can tell. The test sets maskAllInputs to true, which masks the value of the textarea, but the textContent is not masked because that is considered "not an input" and maskAllText is not set to true. Definitely seems incorrect. |
0bccb5b
to
d74b662
Compare
@billyvg fixed the textarea masking. it can still be a little wonky with the default masking functions, b/c one (maskTextFn) excludes whitespace from masking, while the other (maskInputFn) masks every character regardless. |
Should we have a default masking regex/function? @Juice10 @YunFeng0817 Can you take another look when you all get the chance? |
if (type === 'radio' || type === 'checkbox') { | ||
isChecked = (target as HTMLInputElement).checked; | ||
} else if ( | ||
maskInputOptions[tagName.toLowerCase() as keyof MaskInputOptions] || | ||
maskInputOptions[type as keyof MaskInputOptions] | ||
maskInputOptions[type as keyof MaskInputOptions] || | ||
forceMask |
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 don't think we can re-use needMaskingText
/forceMask
here because we could have an unmaskTextSelector
that matches which means forceMask
is false, but maskInputOptions
is true.
forceMask
needs to have 3 outcomes I suppose: 1) matches mask text class, 2) matches unmask, 3) does not match any masking OR unmasking
Only in the 3rd case should we fallback to checking maskInputOptions
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.
not sure i follow
because we could have an unmaskTextSelector that matches which means forceMask is false, but maskInputOptions is true
in this case, it'd still be masked b/c maskInputOptions is true, and the input masking options have priority on inputs like we discussed above?
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.
🤦 sorry - maskAllInputs
sets defaults on maskInputOptions
, overriding the options I pass it.
@Juice10 @YunFeng0817 something I've been playing with in a different branch: I noticed when taking a snapshot or processing a large mutation, we'd be evaluating masking selectors for the same nodes over and over. This commit caches those results temporarily to avoid re-evaluating the selectors when the result for a given node is known already. In my testing, it seems to provide a minor improvement (~10ms faster for a 100ms snapshot). Thought it might provide a bigger boost, so that was a bit of a disappointment, though I've seen it be quite a bit faster in certain configurations. Not sure my approach here is the best/cleanest, but figured I'd throw it out there in case performance concerns are still a sticking point on this PR. |
d74b662
to
2665e50
Compare
I haven't read this PR in detail, but one idea could be that although some sort of |
So #1349 is merged now which I wrote before being aware of this PR; it fixes performance problems with the prior approach namely the constant looking back up the tree when recursing during full snapshot. I've tried to rebase this PR based on that, but the merge is non-trivial, but I might be able to do it given half a day. Possibly it needs a new approach now:
Another option as a first step would be to disallow (Also, it might be nice to first merge the |
@eoghanmurray i'll work on rebasing and modifying the approach |
If you wish to contribute the fix for #874 as a separate PR that might make review easier, we should be able to fasttrack that. |
2665e50
to
fe88c35
Compare
@eoghanmurray i rebased and updated this PR to only address #874. I removed all the new unmasking logic, since I can apply that through the maskText/InputFn callbacks now that they receive the element as a parameter. I also added a check for |
fe88c35
to
fc9b27b
Compare
@eoghanmurray it has been awhile since we commented on this. This PR has been cut down to just address #874 , could we get another look here? |
39defb8
to
b1a1922
Compare
maskInputFn
not passed to initial snapshot*