Skip to content

Commit 6db7ad8

Browse files
authored
fix: masking inputs on change when maskAllInputs:false (#61)
Since `maskInputSelector` is a new configuration item, we were not handling the case for input change when `maskAllInputs:false`. Before, input masking was only done via `maskInputOptions` and `maskAllInputs`.
1 parent d34bf3a commit 6db7ad8

File tree

7 files changed

+1468
-65
lines changed

7 files changed

+1468
-65
lines changed

packages/rrweb-snapshot/src/utils.ts

Lines changed: 50 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,54 @@ export function isShadowRoot(n: Node): n is ShadowRoot {
99
return Boolean(host && host.shadowRoot && host.shadowRoot === n);
1010
}
1111

12+
interface IsInputTypeMasked {
13+
maskInputOptions: MaskInputOptions;
14+
tagName: string;
15+
type: string | number | boolean | null;
16+
}
17+
18+
/**
19+
* Check `maskInputOptions` if the element, based on tag name and `type` attribute, should be masked.
20+
* If `<input>` has no `type`, default to using `type="text"`.
21+
*/
22+
function isInputTypeMasked({
23+
maskInputOptions,
24+
tagName,
25+
type,
26+
}: IsInputTypeMasked) {
27+
return (
28+
maskInputOptions[tagName.toLowerCase() as keyof MaskInputOptions] ||
29+
maskInputOptions[type as keyof MaskInputOptions] ||
30+
// Default to "text" option for inputs without a "type" attribute defined
31+
(tagName === 'input' && !type && maskInputOptions['text'])
32+
);
33+
}
34+
35+
interface HasInputMaskOptions extends IsInputTypeMasked {
36+
maskInputSelector: string | null;
37+
}
38+
39+
/**
40+
* Determine if there are masking options configured and if `maskInputValue` needs to be called
41+
*/
42+
export function hasInputMaskOptions({
43+
tagName,
44+
type,
45+
maskInputOptions,
46+
maskInputSelector,
47+
}: HasInputMaskOptions) {
48+
return (
49+
maskInputSelector || isInputTypeMasked({ maskInputOptions, tagName, type })
50+
);
51+
}
52+
53+
interface MaskInputValue extends HasInputMaskOptions {
54+
input: HTMLElement;
55+
unmaskInputSelector: string | null;
56+
value: string | null;
57+
maskInputFn?: MaskInputFn;
58+
}
59+
1260
export function maskInputValue({
1361
input,
1462
maskInputSelector,
@@ -18,26 +66,15 @@ export function maskInputValue({
1866
type,
1967
value,
2068
maskInputFn,
21-
}: {
22-
input: HTMLElement;
23-
maskInputSelector: string | null;
24-
unmaskInputSelector: string | null;
25-
maskInputOptions: MaskInputOptions;
26-
tagName: string;
27-
type: string | number | boolean | null;
28-
value: string | null;
29-
maskInputFn?: MaskInputFn;
30-
}): string {
69+
}: MaskInputValue): string {
3170
let text = value || '';
3271

3372
if (unmaskInputSelector && input.matches(unmaskInputSelector)) {
3473
return text;
3574
}
3675

3776
if (
38-
maskInputOptions[tagName.toLowerCase() as keyof MaskInputOptions] ||
39-
maskInputOptions[type as keyof MaskInputOptions] ||
40-
(tagName === 'input' && !type && maskInputOptions['text']) || // For inputs without a "type" attribute defined
77+
isInputTypeMasked({ maskInputOptions, tagName, type }) ||
4178
(maskInputSelector && input.matches(maskInputSelector))
4279
) {
4380
if (maskInputFn) {
Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,21 @@
11
import { INode, MaskInputFn, MaskInputOptions } from './types';
22
export declare function isElement(n: Node | INode): n is Element;
33
export declare function isShadowRoot(n: Node): n is ShadowRoot;
4-
export declare function maskInputValue({ input, maskInputSelector, unmaskInputSelector, maskInputOptions, tagName, type, value, maskInputFn, }: {
5-
input: HTMLElement;
6-
maskInputSelector: string | null;
7-
unmaskInputSelector: string | null;
4+
interface IsInputTypeMasked {
85
maskInputOptions: MaskInputOptions;
96
tagName: string;
107
type: string | number | boolean | null;
8+
}
9+
interface HasInputMaskOptions extends IsInputTypeMasked {
10+
maskInputSelector: string | null;
11+
}
12+
export declare function hasInputMaskOptions({ tagName, type, maskInputOptions, maskInputSelector, }: HasInputMaskOptions): string | boolean | undefined;
13+
interface MaskInputValue extends HasInputMaskOptions {
14+
input: HTMLElement;
15+
unmaskInputSelector: string | null;
1116
value: string | null;
1217
maskInputFn?: MaskInputFn;
13-
}): string;
18+
}
19+
export declare function maskInputValue({ input, maskInputSelector, unmaskInputSelector, maskInputOptions, tagName, type, value, maskInputFn, }: MaskInputValue): string;
1420
export declare function is2DCanvasBlank(canvas: HTMLCanvasElement): boolean;
21+
export {};

packages/rrweb/src/record/observer.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import {
22
INode,
3-
MaskInputOptions,
3+
hasInputMaskOptions,
44
maskInputValue,
55
} from '@sentry-internal/rrweb-snapshot';
66
import { FontFaceSet } from 'css-font-loading-module';
@@ -365,15 +365,18 @@ function initInputObserver({
365365
) {
366366
return;
367367
}
368+
368369
let text = (target as HTMLInputElement).value;
369370
let isChecked = false;
370371
if (type === 'radio' || type === 'checkbox') {
371372
isChecked = (target as HTMLInputElement).checked;
372373
} else if (
373-
maskInputOptions[
374-
(target as Element).tagName.toLowerCase() as keyof MaskInputOptions
375-
] ||
376-
maskInputOptions[type as keyof MaskInputOptions]
374+
hasInputMaskOptions({
375+
maskInputOptions,
376+
maskInputSelector,
377+
tagName: (target as HTMLElement).tagName,
378+
type,
379+
})
377380
) {
378381
text = maskInputValue({
379382
input: target as HTMLElement,

0 commit comments

Comments
 (0)