Skip to content

Commit

Permalink
Add options to mask texts (rrweb-io#540)
Browse files Browse the repository at this point in the history
* feat: add options to mask texts

* feat: add the default mask function

* refactor: rename options to identify the difference between  mask text and mask input

* test: add tests about masking

* doc: add options about masking

* chore: bump up rrweb-snapshot version
  • Loading branch information
re-fort authored Apr 22, 2021
1 parent df455c4 commit 18ad3da
Show file tree
Hide file tree
Showing 12 changed files with 895 additions and 10 deletions.
10 changes: 7 additions & 3 deletions guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -142,10 +142,13 @@ The parameter of `rrweb.record` accepts the following options.
| checkoutEveryNms | - | take a full snapshot after every N ms<br />refer to the [checkout](#checkout) chapter |
| blockClass | 'rr-block' | Use a string or RegExp to configure which elements should be blocked, refer to the [privacy](#privacy) chapter |
| ignoreClass | 'rr-ignore' | Use a string or RegExp to configure which elements should be ignored, refer to the [privacy](#privacy) chapter |
| blockSelector | null | Use a string or RegExp to configure which selector should be blocked, refer to the [privacy](#privacy) chapter |
| maskTextClass | 'rr-mask' | Use a string or RegExp to configure which elements should be masked, refer to the [privacy](#privacy) chapter |
| blockSelector | null | Use a string to configure which selector should be blocked, refer to the [privacy](#privacy) chapter |
| maskTextSelector | null | Use a string to configure which selector should be masked, refer to the [privacy](#privacy) chapter |
| maskAllInputs | false | mask all input content as \* |
| maskInputOptions | {} | mask some kinds of input \*<br />refer to the [list](https://github.com/rrweb-io/rrweb-snapshot/blob/6728d12b3cddd96951c86d948578f99ada5749ff/src/types.ts#L72) |
| maskInputFn | - | customize mask input content recording logic |
| maskInputOptions | {} | mask some kinds of input \*<br />refer to the [list](https://github.com/rrweb-io/rrweb-snapshot/blob/6728d12b3cddd96951c86d948578f99ada5749ff/src/types.ts#L72) |
| maskInputFn | - | customize mask input content recording logic |
| maskTextFn | - | customize mask text content recording logic |
| slimDOMOptions | {} | remove unnecessary parts of the DOM <br />refer to the [list](https://github.com/rrweb-io/rrweb-snapshot/blob/6728d12b3cddd96951c86d948578f99ada5749ff/src/types.ts#L91) |
| inlineStylesheet | true | whether to inline the stylesheet in the events |
| hooks | {} | hooks for events<br />refer to the [list](https://github.com/rrweb-io/rrweb/blob/9488deb6d54a5f04350c063d942da5e96ab74075/src/types.ts#L207) |
Expand All @@ -163,6 +166,7 @@ You may find some contents on the webpage which are not willing to be recorded,
- An element with the class name `.rr-ignore` will not record its input events.
- `input[type="password"]` will be ignored as default.
- Mask options to mask the content in input elements.
- A text of elements with the class name `.rr-mask` and its children will be masked.

#### Checkout

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,6 @@
"@xstate/fsm": "^1.4.0",
"fflate": "^0.4.4",
"mitt": "^1.1.3",
"rrweb-snapshot": "^1.1.1"
"rrweb-snapshot": "^1.1.2"
}
}
12 changes: 12 additions & 0 deletions src/record/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,14 @@ function record<T = eventWithTime>(
blockClass = 'rr-block',
blockSelector = null,
ignoreClass = 'rr-ignore',
maskTextClass = 'rr-mask',
maskTextSelector = null,
inlineStylesheet = true,
maskAllInputs,
maskInputOptions: _maskInputOptions,
slimDOMOptions: _slimDOMOptions,
maskInputFn,
maskTextFn,
hooks,
packFn,
sampling = {},
Expand Down Expand Up @@ -203,8 +206,11 @@ function record<T = eventWithTime>(
bypassOptions: {
blockClass,
blockSelector,
maskTextClass,
maskTextSelector,
inlineStylesheet,
maskInputOptions,
maskTextFn,
recordCanvas,
slimDOMOptions,
iframeManager,
Expand All @@ -228,8 +234,11 @@ function record<T = eventWithTime>(
const [node, idNodeMap] = snapshot(document, {
blockClass,
blockSelector,
maskTextClass,
maskTextSelector,
inlineStylesheet,
maskAllInputs: maskInputOptions,
maskTextFn,
slimDOM: slimDOMOptions,
recordCanvas,
onSerialize: (n) => {
Expand Down Expand Up @@ -396,13 +405,16 @@ function record<T = eventWithTime>(
),
blockClass,
ignoreClass,
maskTextClass,
maskTextSelector,
maskInputOptions,
inlineStylesheet,
sampling,
recordCanvas,
collectFonts,
doc,
maskInputFn,
maskTextFn,
logOptions,
blockSelector,
slimDOMOptions,
Expand Down
26 changes: 25 additions & 1 deletion src/record/mutation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,18 @@ import {
SlimDOMOptions,
IGNORED_NODE,
isShadowRoot,
needMaskingText,
} from 'rrweb-snapshot';
import {
mutationRecord,
blockClass,
maskTextClass,
mutationCallBack,
textCursor,
attributeCursor,
removedNodeMutation,
addedNodeMutation,
MaskTextFn,
} from '../types';
import {
mirror,
Expand Down Expand Up @@ -159,8 +162,11 @@ export default class MutationBuffer {
private emissionCallback: mutationCallBack;
private blockClass: blockClass;
private blockSelector: string | null;
private maskTextClass: maskTextClass;
private maskTextSelector: string | null;
private inlineStylesheet: boolean;
private maskInputOptions: MaskInputOptions;
private maskTextFn: MaskTextFn | undefined;
private recordCanvas: boolean;
private slimDOMOptions: SlimDOMOptions;
private doc: Document;
Expand All @@ -172,8 +178,11 @@ export default class MutationBuffer {
cb: mutationCallBack,
blockClass: blockClass,
blockSelector: string | null,
maskTextClass: maskTextClass,
maskTextSelector: string | null,
inlineStylesheet: boolean,
maskInputOptions: MaskInputOptions,
maskTextFn: MaskTextFn | undefined,
recordCanvas: boolean,
slimDOMOptions: SlimDOMOptions,
doc: Document,
Expand All @@ -182,8 +191,11 @@ export default class MutationBuffer {
) {
this.blockClass = blockClass;
this.blockSelector = blockSelector;
this.maskTextClass = maskTextClass;
this.maskTextSelector = maskTextSelector;
this.inlineStylesheet = inlineStylesheet;
this.maskInputOptions = maskInputOptions;
this.maskTextFn = maskTextFn;
this.recordCanvas = recordCanvas;
this.slimDOMOptions = slimDOMOptions;
this.emissionCallback = cb;
Expand Down Expand Up @@ -266,9 +278,12 @@ export default class MutationBuffer {
map: mirror.map,
blockClass: this.blockClass,
blockSelector: this.blockSelector,
maskTextClass: this.maskTextClass,
maskTextSelector: this.maskTextSelector,
skipChild: true,
inlineStylesheet: this.inlineStylesheet,
maskInputOptions: this.maskInputOptions,
maskTextFn: this.maskTextFn,
slimDOMOptions: this.slimDOMOptions,
recordCanvas: this.recordCanvas,
onSerialize: (currentN) => {
Expand Down Expand Up @@ -409,7 +424,16 @@ export default class MutationBuffer {
const value = m.target.textContent;
if (!isBlocked(m.target, this.blockClass) && value !== m.oldValue) {
this.texts.push({
value,
value:
needMaskingText(
m.target,
this.maskTextClass,
this.maskTextSelector,
) && value
? this.maskTextFn
? this.maskTextFn(value)
: value.replace(/[\S]/g, '*')
: value,
node: m.target,
});
}
Expand Down
11 changes: 11 additions & 0 deletions src/record/observer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {
inputCallback,
hookResetter,
blockClass,
maskTextClass,
IncrementalSource,
hooksParam,
Arguments,
Expand All @@ -36,6 +37,7 @@ import {
fontCallback,
fontParam,
MaskInputFn,
MaskTextFn,
logCallback,
LogRecordOptions,
Logger,
Expand All @@ -62,8 +64,11 @@ export function initMutationObserver(
doc: Document,
blockClass: blockClass,
blockSelector: string | null,
maskTextClass: maskTextClass,
maskTextSelector: string | null,
inlineStylesheet: boolean,
maskInputOptions: MaskInputOptions,
maskTextFn: MaskTextFn | undefined,
recordCanvas: boolean,
slimDOMOptions: SlimDOMOptions,
iframeManager: IframeManager,
Expand All @@ -77,8 +82,11 @@ export function initMutationObserver(
cb,
blockClass,
blockSelector,
maskTextClass,
maskTextSelector,
inlineStylesheet,
maskInputOptions,
maskTextFn,
recordCanvas,
slimDOMOptions,
doc,
Expand Down Expand Up @@ -777,8 +785,11 @@ export function initObservers(
o.doc,
o.blockClass,
o.blockSelector,
o.maskTextClass,
o.maskTextSelector,
o.inlineStylesheet,
o.maskInputOptions,
o.maskTextFn,
o.recordCanvas,
o.slimDOMOptions,
o.iframeManager,
Expand Down
8 changes: 7 additions & 1 deletion src/record/shadow-dom-manager.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
import { mutationCallBack, blockClass } from '../types';
import { mutationCallBack, blockClass, maskTextClass, MaskTextFn } from '../types';
import { MaskInputOptions, SlimDOMOptions } from 'rrweb-snapshot';
import { IframeManager } from './iframe-manager';
import { initMutationObserver } from './observer';

type BypassOptions = {
blockClass: blockClass;
blockSelector: string | null;
maskTextClass: maskTextClass;
maskTextSelector: string | null;
inlineStylesheet: boolean;
maskInputOptions: MaskInputOptions;
maskTextFn: MaskTextFn | undefined;
recordCanvas: boolean;
slimDOMOptions: SlimDOMOptions;
iframeManager: IframeManager;
Expand All @@ -31,8 +34,11 @@ export class ShadowDomManager {
doc,
this.bypassOptions.blockClass,
this.bypassOptions.blockSelector,
this.bypassOptions.maskTextClass,
this.bypassOptions.maskTextSelector,
this.bypassOptions.inlineStylesheet,
this.bypassOptions.maskInputOptions,
this.bypassOptions.maskTextFn,
this.bypassOptions.recordCanvas,
this.bypassOptions.slimDOMOptions,
this.bypassOptions.iframeManager,
Expand Down
10 changes: 10 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,8 @@ export type eventWithTime = event & {

export type blockClass = string | RegExp;

export type maskTextClass = string | RegExp;

export type SamplingStrategy = Partial<{
/**
* false means not to record mouse/touch move events
Expand Down Expand Up @@ -196,9 +198,12 @@ export type recordOptions<T> = {
blockClass?: blockClass;
blockSelector?: string;
ignoreClass?: string;
maskTextClass?: maskTextClass;
maskTextSelector?: string;
maskAllInputs?: boolean;
maskInputOptions?: MaskInputOptions;
maskInputFn?: MaskInputFn;
maskTextFn?: MaskTextFn;
slimDOMOptions?: SlimDOMOptions | 'all' | true;
inlineStylesheet?: boolean;
hooks?: hooksParam;
Expand All @@ -222,8 +227,11 @@ export type observerParam = {
blockClass: blockClass;
blockSelector: string | null;
ignoreClass: string;
maskTextClass: maskTextClass;
maskTextSelector: string | null;
maskInputOptions: MaskInputOptions;
maskInputFn?: MaskInputFn;
maskTextFn?: MaskTextFn;
inlineStylesheet: boolean;
styleSheetRuleCb: styleSheetRuleCallback;
canvasMutationCb: canvasMutationCallback;
Expand Down Expand Up @@ -583,6 +591,8 @@ export enum ReplayerEvents {

export type MaskInputFn = (text: string) => string;

export type MaskTextFn = (text: string) => string;

// store the state that would be changed during the process(unmount from dom and mount again)
export type ElementState = {
// [scrollLeft,scrollTop]
Expand Down
Loading

0 comments on commit 18ad3da

Please sign in to comment.