Skip to content

Commit

Permalink
Mask value attribute changes for elements in maskInputOptions (#602)
Browse files Browse the repository at this point in the history
* mask value attribute changes for elements in maskInputOptions

* refactor initInputObserver to use maskInputValue

* add todo

* Fix typo

* upgrade rrweb-snapshot to 1.1.6

* move maskInputValue to rrweb-snapshot
  • Loading branch information
Juice10 authored Jun 30, 2021
1 parent c1158d8 commit ed37401
Show file tree
Hide file tree
Showing 15 changed files with 469 additions and 47 deletions.
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.5"
"rrweb-snapshot": "^1.1.6"
}
}
1 change: 1 addition & 0 deletions src/record/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ function record<T = eventWithTime>(
inlineStylesheet,
maskInputOptions,
maskTextFn,
maskInputFn,
recordCanvas,
sampling,
slimDOMOptions,
Expand Down
19 changes: 17 additions & 2 deletions src/record/mutation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ import {
IGNORED_NODE,
isShadowRoot,
needMaskingText,
maskInputValue,
MaskTextFn,
MaskInputFn,
} from 'rrweb-snapshot';
import {
mutationRecord,
Expand All @@ -17,7 +20,6 @@ import {
attributeCursor,
removedNodeMutation,
addedNodeMutation,
MaskTextFn,
Mirror,
} from '../types';
import {
Expand Down Expand Up @@ -167,6 +169,7 @@ export default class MutationBuffer {
private inlineStylesheet: boolean;
private maskInputOptions: MaskInputOptions;
private maskTextFn: MaskTextFn | undefined;
private maskInputFn: MaskInputFn | undefined;
private recordCanvas: boolean;
private slimDOMOptions: SlimDOMOptions;
private doc: Document;
Expand All @@ -184,6 +187,7 @@ export default class MutationBuffer {
inlineStylesheet: boolean,
maskInputOptions: MaskInputOptions,
maskTextFn: MaskTextFn | undefined,
maskInputFn: MaskInputFn | undefined,
recordCanvas: boolean,
slimDOMOptions: SlimDOMOptions,
doc: Document,
Expand All @@ -198,6 +202,7 @@ export default class MutationBuffer {
this.inlineStylesheet = inlineStylesheet;
this.maskInputOptions = maskInputOptions;
this.maskTextFn = maskTextFn;
this.maskInputFn = maskInputFn;
this.recordCanvas = recordCanvas;
this.slimDOMOptions = slimDOMOptions;
this.emissionCallback = cb;
Expand Down Expand Up @@ -287,6 +292,7 @@ export default class MutationBuffer {
inlineStylesheet: this.inlineStylesheet,
maskInputOptions: this.maskInputOptions,
maskTextFn: this.maskTextFn,
maskInputFn: this.maskInputFn,
slimDOMOptions: this.slimDOMOptions,
recordCanvas: this.recordCanvas,
onSerialize: (currentN) => {
Expand Down Expand Up @@ -443,7 +449,16 @@ export default class MutationBuffer {
break;
}
case 'attributes': {
const value = (m.target as HTMLElement).getAttribute(m.attributeName!);
let value = (m.target as HTMLElement).getAttribute(m.attributeName!);
if (m.attributeName === 'value') {
value = maskInputValue({
maskInputOptions: this.maskInputOptions,
tagName: (m.target as HTMLElement).tagName,
type: (m.target as HTMLElement).getAttribute('type'),
value,
maskInputFn: this.maskInputFn,
});
}
if (isBlocked(m.target, this.blockClass) || value === m.oldValue) {
return;
}
Expand Down
36 changes: 23 additions & 13 deletions src/record/observer.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
import { INode, MaskInputOptions, SlimDOMOptions } from 'rrweb-snapshot';
import {
INode,
MaskInputOptions,
SlimDOMOptions,
maskInputValue,
MaskInputFn,
MaskTextFn,
} from 'rrweb-snapshot';
import { FontFaceDescriptors, FontFaceSet } from 'css-font-loading-module';
import {
throttle,
Expand Down Expand Up @@ -35,8 +42,6 @@ import {
canvasMutationCallback,
fontCallback,
fontParam,
MaskInputFn,
MaskTextFn,
Mirror,
} from '../types';
import MutationBuffer from './mutation';
Expand Down Expand Up @@ -83,6 +88,7 @@ export function initMutationObserver(
inlineStylesheet: boolean,
maskInputOptions: MaskInputOptions,
maskTextFn: MaskTextFn | undefined,
maskInputFn: MaskInputFn | undefined,
recordCanvas: boolean,
slimDOMOptions: SlimDOMOptions,
mirror: Mirror,
Expand All @@ -102,6 +108,7 @@ export function initMutationObserver(
inlineStylesheet,
maskInputOptions,
maskTextFn,
maskInputFn,
recordCanvas,
slimDOMOptions,
doc,
Expand Down Expand Up @@ -366,11 +373,13 @@ function initInputObserver(
] ||
maskInputOptions[type as keyof MaskInputOptions]
) {
if (maskInputFn) {
text = maskInputFn(text);
} else {
text = '*'.repeat(text.length);
}
text = maskInputValue({
maskInputOptions,
tagName: (target as HTMLElement).tagName,
type,
value: text,
maskInputFn,
});
}
cbWithDedup(target, { text, isChecked });
// if a radio was checked
Expand Down Expand Up @@ -476,21 +485,21 @@ function initMediaInteractionObserver(
blockClass: blockClass,
mirror: Mirror,
): listenerHandler {
const handler = (type: MediaInteractions ) => (event: Event) => {
const handler = (type: MediaInteractions) => (event: Event) => {
const target = getEventTarget(event);
if (!target || isBlocked(target as Node, blockClass)) {
return;
}
mediaInteractionCb({
type,
id: mirror.getId(target as INode),
currentTime: (target as HTMLMediaElement).currentTime
currentTime: (target as HTMLMediaElement).currentTime,
});
};
const handlers = [
on('play', handler(MediaInteractions.Play)),
on('pause', handler(MediaInteractions.Pause)),
on('seeked', handler(MediaInteractions.Seeked))
on('play', handler(MediaInteractions.Play)),
on('pause', handler(MediaInteractions.Pause)),
on('seeked', handler(MediaInteractions.Seeked)),
];
return () => {
handlers.forEach((h) => h());
Expand Down Expand Up @@ -716,6 +725,7 @@ export function initObservers(
o.inlineStylesheet,
o.maskInputOptions,
o.maskTextFn,
o.maskInputFn,
o.recordCanvas,
o.slimDOMOptions,
o.mirror,
Expand Down
10 changes: 8 additions & 2 deletions src/record/shadow-dom-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,16 @@ import {
mutationCallBack,
blockClass,
maskTextClass,
MaskTextFn,
Mirror,
scrollCallback,
SamplingStrategy,
} from '../types';
import { MaskInputOptions, SlimDOMOptions } from 'rrweb-snapshot';
import {
MaskInputOptions,
SlimDOMOptions,
MaskTextFn,
MaskInputFn,
} from 'rrweb-snapshot';
import { IframeManager } from './iframe-manager';
import { initMutationObserver, initScrollObserver } from './observer';

Expand All @@ -19,6 +23,7 @@ type BypassOptions = {
inlineStylesheet: boolean;
maskInputOptions: MaskInputOptions;
maskTextFn: MaskTextFn | undefined;
maskInputFn: MaskInputFn | undefined;
recordCanvas: boolean;
sampling: SamplingStrategy;
slimDOMOptions: SlimDOMOptions;
Expand Down Expand Up @@ -54,6 +59,7 @@ export class ShadowDomManager {
this.bypassOptions.inlineStylesheet,
this.bypassOptions.maskInputOptions,
this.bypassOptions.maskTextFn,
this.bypassOptions.maskInputFn,
this.bypassOptions.recordCanvas,
this.bypassOptions.slimDOMOptions,
this.mirror,
Expand Down
6 changes: 2 additions & 4 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import {
INode,
MaskInputOptions,
SlimDOMOptions,
MaskInputFn,
MaskTextFn,
} from 'rrweb-snapshot';
import { PackFn, UnpackFn } from './packer/base';
import { FontFaceDescriptors } from 'css-font-loading-module';
Expand Down Expand Up @@ -544,10 +546,6 @@ export enum ReplayerEvents {
PlayBack = 'play-back',
}

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
24 changes: 14 additions & 10 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ export function createMirror(): Mirror {
delete this.map[id];
if (n.childNodes) {
n.childNodes.forEach((child) =>
this.removeNodeFromMap(child as Node as INode),
this.removeNodeFromMap((child as Node) as INode),
);
}
},
Expand Down Expand Up @@ -275,7 +275,7 @@ export function isAncestorRemoved(target: INode, mirror: Mirror): boolean {
if (!target.parentNode) {
return true;
}
return isAncestorRemoved(target.parentNode as unknown as INode, mirror);
return isAncestorRemoved((target.parentNode as unknown) as INode, mirror);
}

export function isTouchEvent(
Expand All @@ -286,13 +286,13 @@ export function isTouchEvent(

export function polyfill(win = window) {
if ('NodeList' in win && !win.NodeList.prototype.forEach) {
win.NodeList.prototype.forEach = Array.prototype
.forEach as unknown as NodeList['forEach'];
win.NodeList.prototype.forEach = (Array.prototype
.forEach as unknown) as NodeList['forEach'];
}

if ('DOMTokenList' in win && !win.DOMTokenList.prototype.forEach) {
win.DOMTokenList.prototype.forEach = Array.prototype
.forEach as unknown as DOMTokenList['forEach'];
win.DOMTokenList.prototype.forEach = (Array.prototype
.forEach as unknown) as DOMTokenList['forEach'];
}

// https://github.com/Financial-Times/polyfill-service/pull/183
Expand Down Expand Up @@ -396,7 +396,7 @@ export class TreeIndex {
const node = mirror.getNode(id);
node?.childNodes.forEach((childNode) => {
if ('__sn' in childNode) {
deepRemoveFromMirror((childNode as unknown as INode).__sn.id);
deepRemoveFromMirror(((childNode as unknown) as INode).__sn.id);
}
});
};
Expand Down Expand Up @@ -460,8 +460,12 @@ export class TreeIndex {
scrollMap: TreeIndex['scrollMap'];
inputMap: TreeIndex['inputMap'];
} {
const { tree, removeNodeMutations, textMutations, attributeMutations } =
this;
const {
tree,
removeNodeMutations,
textMutations,
attributeMutations,
} = this;

const batchMutationData: mutationData = {
source: IncrementalSource.Mutation,
Expand Down Expand Up @@ -650,5 +654,5 @@ export function getBaseDimension(
export function hasShadowRoot<T extends Node>(
n: T,
): n is T & { shadowRoot: ShadowRoot } {
return Boolean((n as unknown as Element)?.shadowRoot);
return Boolean(((n as unknown) as Element)?.shadowRoot);
}
Loading

0 comments on commit ed37401

Please sign in to comment.