Skip to content

Commit

Permalink
fix: Mask <option> values for selects & radio/checkbox value (#75)
Browse files Browse the repository at this point in the history
  • Loading branch information
mydea committed Mar 3, 2023
1 parent 2efad19 commit 11d0458
Show file tree
Hide file tree
Showing 7 changed files with 823 additions and 390 deletions.
62 changes: 53 additions & 9 deletions packages/rrweb-snapshot/src/snapshot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -475,8 +475,8 @@ function serializeNode(
} = options;
// Only record root id when document object is not the base document
let rootId: number | undefined;
if ((doc as unknown as INode).__sn) {
const docId = (doc as unknown as INode).__sn.id;
if (((doc as unknown) as INode).__sn) {
const docId = ((doc as unknown) as INode).__sn.id;
rootId = docId === 1 ? undefined : docId;
}
switch (n.nodeType) {
Expand Down Expand Up @@ -561,22 +561,29 @@ function serializeNode(
attributes._cssText = absoluteToStylesheet(cssText, getHref());
}
}

// form fields
if (
tagName === 'input' ||
tagName === 'textarea' ||
tagName === 'select'
tagName === 'select' ||
tagName === 'option'
) {
const value = (n as HTMLInputElement | HTMLTextAreaElement).value;
const el = n as
| HTMLInputElement
| HTMLTextAreaElement
| HTMLSelectElement
| HTMLOptionElement;
const value = getInputValue(tagName, el, attributes);
const checked = (n as HTMLInputElement).checked;

if (
attributes.type !== 'radio' &&
attributes.type !== 'checkbox' &&
attributes.type !== 'submit' &&
attributes.type !== 'button' &&
value
) {
attributes.value = maskInputValue({
input: n as HTMLElement,
input: el,
type: attributes.type,
tagName,
value,
Expand All @@ -585,10 +592,12 @@ function serializeNode(
maskInputOptions,
maskInputFn,
});
} else if ((n as HTMLInputElement).checked) {
attributes.checked = (n as HTMLInputElement).checked;
}
if (checked) {
attributes.checked = checked;
}
}

if (tagName === 'option') {
if ((n as HTMLOptionElement).selected && !maskInputOptions['select']) {
attributes.selected = true;
Expand Down Expand Up @@ -741,6 +750,20 @@ function serializeNode(
if (parentTagName === 'TEXTAREA' && textContent) {
// textarea textContent should be masked via `value` attributes
textContent = '';
} else if (parentTagName === 'OPTION' && textContent) {
// mask option text like value
const option = n.parentNode as HTMLOptionElement;

textContent = maskInputValue({
input: option,
type: null,
tagName: parentTagName,
value: textContent,
maskInputSelector,
unmaskInputSelector,
maskInputOptions,
maskInputFn,
});
} else if (
!isStyle &&
!isScript &&
Expand Down Expand Up @@ -1269,3 +1292,24 @@ function skipAttribute(
(tagName === 'video' || tagName === 'audio') && attributeName === 'autoplay'
);
}

function getInputValue(
tagName: string,
el:
| HTMLInputElement
| HTMLTextAreaElement
| HTMLSelectElement
| HTMLOptionElement,
attributes: attributes,
): string {
if (
tagName === 'input' &&
(attributes.type === 'radio' || attributes.type === 'checkbox')
) {
// checkboxes & radio buttons return `on` as their el.value when no value is specified
// we only want to get the value if it is specified as `value='xxx'`
return el.getAttribute('value') || '';
}

return el.value;
}
2 changes: 2 additions & 0 deletions packages/rrweb-snapshot/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ export type MaskInputOptions = Partial<{
textarea: boolean;
select: boolean;
password: boolean;
radio: boolean;
checkbox: boolean;
}>;

export type SlimDOMOptions = Partial<{
Expand Down
5 changes: 5 additions & 0 deletions packages/rrweb-snapshot/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ function isInputTypeMasked({
tagName,
type,
}: IsInputTypeMasked) {
// Handle options as part of select
if (tagName.toLowerCase() === 'option') {
tagName = 'select';
}

return (
maskInputOptions[tagName.toLowerCase() as keyof MaskInputOptions] ||
maskInputOptions[type as keyof MaskInputOptions] ||
Expand Down
2 changes: 2 additions & 0 deletions packages/rrweb-snapshot/typings/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ export type MaskInputOptions = Partial<{
textarea: boolean;
select: boolean;
password: boolean;
radio: boolean;
checkbox: boolean;
}>;
export type SlimDOMOptions = Partial<{
script: boolean;
Expand Down
2 changes: 2 additions & 0 deletions packages/rrweb/src/record/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@ function record<T = eventWithTime>(
textarea: true,
select: true,
password: true,
radio: true,
checkbox: true,
}
: _maskInputOptions !== undefined
? _maskInputOptions
Expand Down
Loading

0 comments on commit 11d0458

Please sign in to comment.