Fix a code path where masking could be skipped on textareas (#1599)

* Fixes #1596
This commit is contained in:
Eoghan Murray
2026-04-01 12:00:00 +08:00
committed by GitHub
parent ecac346b4c
commit c144c71810
4 changed files with 180 additions and 5 deletions

View File

@@ -0,0 +1,5 @@
---
"rrweb": patch
---
#1596 Add masking for innerText mutations on textarea elements

View File

@@ -533,10 +533,18 @@ export default class MutationBuffer {
this.attributes.push(item);
this.attributeMap.set(textarea, item);
}
item.attributes.value = Array.from(
const value = Array.from(
dom.childNodes(textarea),
(cn) => dom.textContent(cn) || '',
).join('');
item.attributes.value = maskInputValue({
element: textarea,
maskInputOptions: this.maskInputOptions,
tagName: textarea.tagName,
type: getInputType(textarea),
value,
maskInputFn: this.maskInputFn,
});
};
private processMutation = (m: mutationRecord) => {

View File

@@ -9964,6 +9964,21 @@ exports[`record integration tests > should not record input values if dynamicall
{
\\"parentId\\": 14,
\\"nextId\\": 16,
\\"node\\": {
\\"type\\": 2,
\\"tagName\\": \\"textarea\\",
\\"attributes\\": {
\\"id\\": \\"textarea\\",
\\"size\\": \\"50\\",
\\"value\\": \\"*************************\\"
},
\\"childNodes\\": [],
\\"id\\": 21
}
},
{
\\"parentId\\": 14,
\\"nextId\\": 21,
\\"node\\": {
\\"type\\": 2,
\\"tagName\\": \\"input\\",
@@ -9973,7 +9988,7 @@ exports[`record integration tests > should not record input values if dynamicall
\\"value\\": \\"**********************\\"
},
\\"childNodes\\": [],
\\"id\\": 21
\\"id\\": 22
}
}
]
@@ -9985,9 +10000,61 @@ exports[`record integration tests > should not record input values if dynamicall
\\"source\\": 5,
\\"text\\": \\"**********************\\",
\\"isChecked\\": false,
\\"id\\": 22
}
},
{
\\"type\\": 3,
\\"data\\": {
\\"source\\": 5,
\\"text\\": \\"*************************\\",
\\"isChecked\\": false,
\\"id\\": 21
}
},
{
\\"type\\": 3,
\\"data\\": {
\\"source\\": 2,
\\"type\\": 5,
\\"id\\": 22
}
},
{
\\"type\\": 3,
\\"data\\": {
\\"source\\": 5,
\\"text\\": \\"***********************\\",
\\"isChecked\\": false,
\\"id\\": 22
}
},
{
\\"type\\": 3,
\\"data\\": {
\\"source\\": 5,
\\"text\\": \\"************************\\",
\\"isChecked\\": false,
\\"id\\": 22
}
},
{
\\"type\\": 3,
\\"data\\": {
\\"source\\": 5,
\\"text\\": \\"*************************\\",
\\"isChecked\\": false,
\\"id\\": 22
}
},
{
\\"type\\": 3,
\\"data\\": {
\\"source\\": 2,
\\"type\\": 6,
\\"id\\": 22
}
},
{
\\"type\\": 3,
\\"data\\": {
@@ -10000,7 +10067,7 @@ exports[`record integration tests > should not record input values if dynamicall
\\"type\\": 3,
\\"data\\": {
\\"source\\": 5,
\\"text\\": \\"***********************\\",
\\"text\\": \\"**************************\\",
\\"isChecked\\": false,
\\"id\\": 21
}
@@ -10009,7 +10076,7 @@ exports[`record integration tests > should not record input values if dynamicall
\\"type\\": 3,
\\"data\\": {
\\"source\\": 5,
\\"text\\": \\"************************\\",
\\"text\\": \\"***************************\\",
\\"isChecked\\": false,
\\"id\\": 21
}
@@ -10018,10 +10085,68 @@ exports[`record integration tests > should not record input values if dynamicall
\\"type\\": 3,
\\"data\\": {
\\"source\\": 5,
\\"text\\": \\"*************************\\",
\\"text\\": \\"****************************\\",
\\"isChecked\\": false,
\\"id\\": 21
}
},
{
\\"type\\": 3,
\\"data\\": {
\\"source\\": 5,
\\"text\\": \\"**********************************************\\",
\\"isChecked\\": false,
\\"id\\": 22
}
},
{
\\"type\\": 3,
\\"data\\": {
\\"source\\": 5,
\\"text\\": \\"*************************************************\\",
\\"isChecked\\": false,
\\"id\\": 21
}
},
{
\\"type\\": 3,
\\"data\\": {
\\"source\\": 0,
\\"texts\\": [],
\\"attributes\\": [
{
\\"id\\": 22,
\\"attributes\\": {
\\"value\\": \\"**********************************************************************************************\\"
}
},
{
\\"id\\": 21,
\\"attributes\\": {
\\"value\\": \\"*************************************************************************************************\\"
}
}
],
\\"removes\\": [],
\\"adds\\": []
}
},
{
\\"type\\": 3,
\\"data\\": {
\\"source\\": 0,
\\"texts\\": [],
\\"attributes\\": [
{
\\"id\\": 21,
\\"attributes\\": {
\\"value\\": \\"****************************************************************\\"
}
}
],
\\"removes\\": [],
\\"adds\\": []
}
}
]"
`;

View File

@@ -783,9 +783,46 @@ describe('record integration tests', function (this: ISuite) {
const nextElement = document.querySelector('#one')!;
nextElement.parentNode!.insertBefore(el, nextElement);
const ta = document.createElement('textarea');
ta.size = 50;
ta.id = 'textarea';
ta.setAttribute('size', '50');
ta.value = 'textarea should be masked';
nextElement.parentNode!.insertBefore(ta, nextElement);
});
await page.type('#input', 'moo');
await page.type('#textarea', 'boo');
await page.evaluate(() => {
const el = document.querySelector('input');
el.value = 'input attribute mutation should also be masked';
const ta = document.querySelector('textarea');
ta.value = 'textarea attribute mutation should also be masked';
});
await page.evaluate(() => {
const el = document.querySelector('input');
el.setAttribute(
'value',
"input attribute mutation should also be masked (even though the new value doesn't take effect)",
);
const ta = document.querySelector('textarea');
ta.setAttribute(
'value',
"textarea attribute mutation should also be masked (even though the new value doesn't take effect)",
);
});
await page.evaluate(() => {
const ta = document.querySelector('textarea');
ta.innerText =
'textarea attribute mutation via innerText should also be masked ';
});
await assertSnapshot(page);
});