feat: Ensure password inputs are masked when switching type (#1170)
* feat: Ensure password inputs are masked when switching type Apply formatting changes use data- attribute ref: Ensure type is always lowercased add changeset * extract into util * Apply formatting changes
This commit is contained in:
6
.changeset/new-snakes-call.md
Normal file
6
.changeset/new-snakes-call.md
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
'rrweb-snapshot': minor
|
||||||
|
'rrweb': minor
|
||||||
|
---
|
||||||
|
|
||||||
|
feat: Ensure password inputs remain masked when switching input type
|
||||||
@@ -674,8 +674,13 @@ function serializeElementNode(
|
|||||||
attributes.type !== 'button' &&
|
attributes.type !== 'button' &&
|
||||||
value
|
value
|
||||||
) {
|
) {
|
||||||
|
const type: string | null = n.hasAttribute('data-rr-is-password')
|
||||||
|
? 'password'
|
||||||
|
: typeof attributes.type === 'string'
|
||||||
|
? attributes.type.toLowerCase()
|
||||||
|
: null;
|
||||||
attributes.value = maskInputValue({
|
attributes.value = maskInputValue({
|
||||||
type: attributes.type,
|
type,
|
||||||
tagName,
|
tagName,
|
||||||
value,
|
value,
|
||||||
maskInputOptions,
|
maskInputOptions,
|
||||||
|
|||||||
@@ -162,14 +162,16 @@ export function maskInputValue({
|
|||||||
}: {
|
}: {
|
||||||
maskInputOptions: MaskInputOptions;
|
maskInputOptions: MaskInputOptions;
|
||||||
tagName: string;
|
tagName: string;
|
||||||
type: string | number | boolean | null;
|
type: string | null;
|
||||||
value: string | null;
|
value: string | null;
|
||||||
maskInputFn?: MaskInputFn;
|
maskInputFn?: MaskInputFn;
|
||||||
}): string {
|
}): string {
|
||||||
let text = value || '';
|
let text = value || '';
|
||||||
|
const actualType = type && type.toLowerCase();
|
||||||
|
|
||||||
if (
|
if (
|
||||||
maskInputOptions[tagName.toLowerCase() as keyof MaskInputOptions] ||
|
maskInputOptions[tagName.toLowerCase() as keyof MaskInputOptions] ||
|
||||||
maskInputOptions[type as keyof MaskInputOptions]
|
(actualType && maskInputOptions[actualType as keyof MaskInputOptions])
|
||||||
) {
|
) {
|
||||||
if (maskInputFn) {
|
if (maskInputFn) {
|
||||||
text = maskInputFn(text);
|
text = maskInputFn(text);
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import {
|
|||||||
isSerializedStylesheet,
|
isSerializedStylesheet,
|
||||||
inDom,
|
inDom,
|
||||||
getShadowHost,
|
getShadowHost,
|
||||||
|
getInputType,
|
||||||
} from '../utils';
|
} from '../utils';
|
||||||
|
|
||||||
type DoubleLinkedListNode = {
|
type DoubleLinkedListNode = {
|
||||||
@@ -488,11 +489,14 @@ export default class MutationBuffer {
|
|||||||
const target = m.target as HTMLElement;
|
const target = m.target as HTMLElement;
|
||||||
let attributeName = m.attributeName as string;
|
let attributeName = m.attributeName as string;
|
||||||
let value = (m.target as HTMLElement).getAttribute(attributeName);
|
let value = (m.target as HTMLElement).getAttribute(attributeName);
|
||||||
|
|
||||||
if (attributeName === 'value') {
|
if (attributeName === 'value') {
|
||||||
|
const type = getInputType(target);
|
||||||
|
|
||||||
value = maskInputValue({
|
value = maskInputValue({
|
||||||
maskInputOptions: this.maskInputOptions,
|
maskInputOptions: this.maskInputOptions,
|
||||||
tagName: (m.target as HTMLElement).tagName,
|
tagName: target.tagName,
|
||||||
type: (m.target as HTMLElement).getAttribute('type'),
|
type,
|
||||||
value,
|
value,
|
||||||
maskInputFn: this.maskInputFn,
|
maskInputFn: this.maskInputFn,
|
||||||
});
|
});
|
||||||
@@ -527,6 +531,17 @@ export default class MutationBuffer {
|
|||||||
};
|
};
|
||||||
this.attributes.push(item);
|
this.attributes.push(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Keep this property on inputs that used to be password inputs
|
||||||
|
// This is used to ensure we do not unmask value when using e.g. a "Show password" type button
|
||||||
|
if (
|
||||||
|
attributeName === 'type' &&
|
||||||
|
target.tagName === 'INPUT' &&
|
||||||
|
(m.oldValue || '').toLowerCase() === 'password'
|
||||||
|
) {
|
||||||
|
target.setAttribute('data-rr-is-password', 'true');
|
||||||
|
}
|
||||||
|
|
||||||
if (attributeName === 'style') {
|
if (attributeName === 'style') {
|
||||||
const old = this.doc.createElement('span');
|
const old = this.doc.createElement('span');
|
||||||
if (m.oldValue) {
|
if (m.oldValue) {
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import {
|
|||||||
throttle,
|
throttle,
|
||||||
on,
|
on,
|
||||||
hookSetter,
|
hookSetter,
|
||||||
|
getInputType,
|
||||||
getWindowScroll,
|
getWindowScroll,
|
||||||
getWindowHeight,
|
getWindowHeight,
|
||||||
getWindowWidth,
|
getWindowWidth,
|
||||||
@@ -338,39 +339,42 @@ function initInputObserver({
|
|||||||
userTriggeredOnInput,
|
userTriggeredOnInput,
|
||||||
}: observerParam): listenerHandler {
|
}: observerParam): listenerHandler {
|
||||||
function eventHandler(event: Event) {
|
function eventHandler(event: Event) {
|
||||||
let target = getEventTarget(event);
|
let target = getEventTarget(event) as HTMLElement | null;
|
||||||
const userTriggered = event.isTrusted;
|
const userTriggered = event.isTrusted;
|
||||||
|
const tagName = target && target.tagName;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If a site changes the value 'selected' of an option element, the value of its parent element, usually a select element, will be changed as well.
|
* If a site changes the value 'selected' of an option element, the value of its parent element, usually a select element, will be changed as well.
|
||||||
* We can treat this change as a value change of the select element the current target belongs to.
|
* We can treat this change as a value change of the select element the current target belongs to.
|
||||||
*/
|
*/
|
||||||
if (target && (target as Element).tagName === 'OPTION')
|
if (target && tagName === 'OPTION') {
|
||||||
target = (target as Element).parentElement;
|
target = target.parentElement;
|
||||||
|
}
|
||||||
if (
|
if (
|
||||||
!target ||
|
!target ||
|
||||||
!(target as Element).tagName ||
|
!tagName ||
|
||||||
INPUT_TAGS.indexOf((target as Element).tagName) < 0 ||
|
INPUT_TAGS.indexOf(tagName) < 0 ||
|
||||||
isBlocked(target as Node, blockClass, blockSelector, true)
|
isBlocked(target as Node, blockClass, blockSelector, true)
|
||||||
) {
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const type: string | undefined = (target as HTMLInputElement).type;
|
|
||||||
if ((target as HTMLElement).classList.contains(ignoreClass)) {
|
if (target.classList.contains(ignoreClass)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let text = (target as HTMLInputElement).value;
|
let text = (target as HTMLInputElement).value;
|
||||||
let isChecked = false;
|
let isChecked = false;
|
||||||
|
const type: Lowercase<string> = getInputType(target) || '';
|
||||||
|
|
||||||
if (type === 'radio' || type === 'checkbox') {
|
if (type === 'radio' || type === 'checkbox') {
|
||||||
isChecked = (target as HTMLInputElement).checked;
|
isChecked = (target as HTMLInputElement).checked;
|
||||||
} else if (
|
} else if (
|
||||||
maskInputOptions[
|
maskInputOptions[tagName.toLowerCase() as keyof MaskInputOptions] ||
|
||||||
(target as Element).tagName.toLowerCase() as keyof MaskInputOptions
|
|
||||||
] ||
|
|
||||||
maskInputOptions[type as keyof MaskInputOptions]
|
maskInputOptions[type as keyof MaskInputOptions]
|
||||||
) {
|
) {
|
||||||
text = maskInputValue({
|
text = maskInputValue({
|
||||||
maskInputOptions,
|
maskInputOptions,
|
||||||
tagName: (target as HTMLElement).tagName,
|
tagName,
|
||||||
type,
|
type,
|
||||||
value: text,
|
value: text,
|
||||||
maskInputFn,
|
maskInputFn,
|
||||||
|
|||||||
@@ -563,3 +563,17 @@ export function inDom(n: Node): boolean {
|
|||||||
if (!doc) return false;
|
if (!doc) return false;
|
||||||
return doc.contains(n) || shadowHostInDom(n);
|
return doc.contains(n) || shadowHostInDom(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the type of an input element.
|
||||||
|
* This takes care of the case where a password input is changed to a text input.
|
||||||
|
* In this case, we continue to consider this of type password, in order to avoid leaking sensitive data
|
||||||
|
* where passwords should be masked.
|
||||||
|
*/
|
||||||
|
export function getInputType(element: HTMLElement): Lowercase<string> | null {
|
||||||
|
return element.hasAttribute('data-rr-is-password')
|
||||||
|
? 'password'
|
||||||
|
: element.hasAttribute('type')
|
||||||
|
? (element.getAttribute('type')!.toLowerCase() as Lowercase<string>)
|
||||||
|
: null;
|
||||||
|
}
|
||||||
|
|||||||
@@ -5102,6 +5102,451 @@ exports[`record integration tests should handle recursive console messages 1`] =
|
|||||||
]"
|
]"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports[`record integration tests should mask password value attribute with maskInputOptions 1`] = `
|
||||||
|
"[
|
||||||
|
{
|
||||||
|
\\"type\\": 0,
|
||||||
|
\\"data\\": {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
\\"type\\": 1,
|
||||||
|
\\"data\\": {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
\\"type\\": 4,
|
||||||
|
\\"data\\": {
|
||||||
|
\\"href\\": \\"about:blank\\",
|
||||||
|
\\"width\\": 1920,
|
||||||
|
\\"height\\": 1080
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
\\"type\\": 2,
|
||||||
|
\\"data\\": {
|
||||||
|
\\"node\\": {
|
||||||
|
\\"type\\": 0,
|
||||||
|
\\"childNodes\\": [
|
||||||
|
{
|
||||||
|
\\"type\\": 1,
|
||||||
|
\\"name\\": \\"html\\",
|
||||||
|
\\"publicId\\": \\"\\",
|
||||||
|
\\"systemId\\": \\"\\",
|
||||||
|
\\"id\\": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
\\"type\\": 2,
|
||||||
|
\\"tagName\\": \\"html\\",
|
||||||
|
\\"attributes\\": {
|
||||||
|
\\"lang\\": \\"en\\"
|
||||||
|
},
|
||||||
|
\\"childNodes\\": [
|
||||||
|
{
|
||||||
|
\\"type\\": 2,
|
||||||
|
\\"tagName\\": \\"head\\",
|
||||||
|
\\"attributes\\": {},
|
||||||
|
\\"childNodes\\": [
|
||||||
|
{
|
||||||
|
\\"type\\": 3,
|
||||||
|
\\"textContent\\": \\"\\\\n \\",
|
||||||
|
\\"id\\": 5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
\\"type\\": 2,
|
||||||
|
\\"tagName\\": \\"meta\\",
|
||||||
|
\\"attributes\\": {
|
||||||
|
\\"charset\\": \\"UTF-8\\"
|
||||||
|
},
|
||||||
|
\\"childNodes\\": [],
|
||||||
|
\\"id\\": 6
|
||||||
|
},
|
||||||
|
{
|
||||||
|
\\"type\\": 3,
|
||||||
|
\\"textContent\\": \\"\\\\n \\",
|
||||||
|
\\"id\\": 7
|
||||||
|
},
|
||||||
|
{
|
||||||
|
\\"type\\": 2,
|
||||||
|
\\"tagName\\": \\"meta\\",
|
||||||
|
\\"attributes\\": {
|
||||||
|
\\"http-equiv\\": \\"X-UA-Compatible\\",
|
||||||
|
\\"content\\": \\"IE=edge\\"
|
||||||
|
},
|
||||||
|
\\"childNodes\\": [],
|
||||||
|
\\"id\\": 8
|
||||||
|
},
|
||||||
|
{
|
||||||
|
\\"type\\": 3,
|
||||||
|
\\"textContent\\": \\"\\\\n \\",
|
||||||
|
\\"id\\": 9
|
||||||
|
},
|
||||||
|
{
|
||||||
|
\\"type\\": 2,
|
||||||
|
\\"tagName\\": \\"meta\\",
|
||||||
|
\\"attributes\\": {
|
||||||
|
\\"name\\": \\"viewport\\",
|
||||||
|
\\"content\\": \\"width=device-width, initial-scale=1.0\\"
|
||||||
|
},
|
||||||
|
\\"childNodes\\": [],
|
||||||
|
\\"id\\": 10
|
||||||
|
},
|
||||||
|
{
|
||||||
|
\\"type\\": 3,
|
||||||
|
\\"textContent\\": \\"\\\\n \\",
|
||||||
|
\\"id\\": 11
|
||||||
|
},
|
||||||
|
{
|
||||||
|
\\"type\\": 2,
|
||||||
|
\\"tagName\\": \\"title\\",
|
||||||
|
\\"attributes\\": {},
|
||||||
|
\\"childNodes\\": [
|
||||||
|
{
|
||||||
|
\\"type\\": 3,
|
||||||
|
\\"textContent\\": \\"Document\\",
|
||||||
|
\\"id\\": 13
|
||||||
|
}
|
||||||
|
],
|
||||||
|
\\"id\\": 12
|
||||||
|
},
|
||||||
|
{
|
||||||
|
\\"type\\": 3,
|
||||||
|
\\"textContent\\": \\"\\\\n \\",
|
||||||
|
\\"id\\": 14
|
||||||
|
}
|
||||||
|
],
|
||||||
|
\\"id\\": 4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
\\"type\\": 3,
|
||||||
|
\\"textContent\\": \\"\\\\n \\",
|
||||||
|
\\"id\\": 15
|
||||||
|
},
|
||||||
|
{
|
||||||
|
\\"type\\": 2,
|
||||||
|
\\"tagName\\": \\"body\\",
|
||||||
|
\\"attributes\\": {},
|
||||||
|
\\"childNodes\\": [
|
||||||
|
{
|
||||||
|
\\"type\\": 3,
|
||||||
|
\\"textContent\\": \\"\\\\n \\",
|
||||||
|
\\"id\\": 17
|
||||||
|
},
|
||||||
|
{
|
||||||
|
\\"type\\": 2,
|
||||||
|
\\"tagName\\": \\"input\\",
|
||||||
|
\\"attributes\\": {
|
||||||
|
\\"type\\": \\"password\\",
|
||||||
|
\\"id\\": \\"password\\"
|
||||||
|
},
|
||||||
|
\\"childNodes\\": [],
|
||||||
|
\\"id\\": 18
|
||||||
|
},
|
||||||
|
{
|
||||||
|
\\"type\\": 3,
|
||||||
|
\\"textContent\\": \\"\\\\n \\",
|
||||||
|
\\"id\\": 19
|
||||||
|
},
|
||||||
|
{
|
||||||
|
\\"type\\": 2,
|
||||||
|
\\"tagName\\": \\"button\\",
|
||||||
|
\\"attributes\\": {
|
||||||
|
\\"type\\": \\"button\\",
|
||||||
|
\\"id\\": \\"show-password\\"
|
||||||
|
},
|
||||||
|
\\"childNodes\\": [
|
||||||
|
{
|
||||||
|
\\"type\\": 3,
|
||||||
|
\\"textContent\\": \\"Toggle show password\\",
|
||||||
|
\\"id\\": 21
|
||||||
|
}
|
||||||
|
],
|
||||||
|
\\"id\\": 20
|
||||||
|
},
|
||||||
|
{
|
||||||
|
\\"type\\": 3,
|
||||||
|
\\"textContent\\": \\"\\\\n \\",
|
||||||
|
\\"id\\": 22
|
||||||
|
},
|
||||||
|
{
|
||||||
|
\\"type\\": 2,
|
||||||
|
\\"tagName\\": \\"script\\",
|
||||||
|
\\"attributes\\": {},
|
||||||
|
\\"childNodes\\": [
|
||||||
|
{
|
||||||
|
\\"type\\": 3,
|
||||||
|
\\"textContent\\": \\"SCRIPT_PLACEHOLDER\\",
|
||||||
|
\\"id\\": 24
|
||||||
|
}
|
||||||
|
],
|
||||||
|
\\"id\\": 23
|
||||||
|
},
|
||||||
|
{
|
||||||
|
\\"type\\": 3,
|
||||||
|
\\"textContent\\": \\"\\\\n \\\\n \\",
|
||||||
|
\\"id\\": 25
|
||||||
|
},
|
||||||
|
{
|
||||||
|
\\"type\\": 2,
|
||||||
|
\\"tagName\\": \\"script\\",
|
||||||
|
\\"attributes\\": {},
|
||||||
|
\\"childNodes\\": [
|
||||||
|
{
|
||||||
|
\\"type\\": 3,
|
||||||
|
\\"textContent\\": \\"SCRIPT_PLACEHOLDER\\",
|
||||||
|
\\"id\\": 27
|
||||||
|
}
|
||||||
|
],
|
||||||
|
\\"id\\": 26
|
||||||
|
},
|
||||||
|
{
|
||||||
|
\\"type\\": 3,
|
||||||
|
\\"textContent\\": \\"\\\\n \\\\n \\\\n\\\\n\\",
|
||||||
|
\\"id\\": 28
|
||||||
|
}
|
||||||
|
],
|
||||||
|
\\"id\\": 16
|
||||||
|
}
|
||||||
|
],
|
||||||
|
\\"id\\": 3
|
||||||
|
}
|
||||||
|
],
|
||||||
|
\\"id\\": 1
|
||||||
|
},
|
||||||
|
\\"initialOffset\\": {
|
||||||
|
\\"left\\": 0,
|
||||||
|
\\"top\\": 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
\\"type\\": 3,
|
||||||
|
\\"data\\": {
|
||||||
|
\\"source\\": 2,
|
||||||
|
\\"type\\": 5,
|
||||||
|
\\"id\\": 18
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
\\"type\\": 3,
|
||||||
|
\\"data\\": {
|
||||||
|
\\"source\\": 5,
|
||||||
|
\\"text\\": \\"*\\",
|
||||||
|
\\"isChecked\\": false,
|
||||||
|
\\"id\\": 18
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
\\"type\\": 3,
|
||||||
|
\\"data\\": {
|
||||||
|
\\"source\\": 5,
|
||||||
|
\\"text\\": \\"**\\",
|
||||||
|
\\"isChecked\\": false,
|
||||||
|
\\"id\\": 18
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
\\"type\\": 3,
|
||||||
|
\\"data\\": {
|
||||||
|
\\"source\\": 5,
|
||||||
|
\\"text\\": \\"***\\",
|
||||||
|
\\"isChecked\\": false,
|
||||||
|
\\"id\\": 18
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
\\"type\\": 3,
|
||||||
|
\\"data\\": {
|
||||||
|
\\"source\\": 5,
|
||||||
|
\\"text\\": \\"****\\",
|
||||||
|
\\"isChecked\\": false,
|
||||||
|
\\"id\\": 18
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
\\"type\\": 3,
|
||||||
|
\\"data\\": {
|
||||||
|
\\"source\\": 5,
|
||||||
|
\\"text\\": \\"*****\\",
|
||||||
|
\\"isChecked\\": false,
|
||||||
|
\\"id\\": 18
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
\\"type\\": 3,
|
||||||
|
\\"data\\": {
|
||||||
|
\\"source\\": 5,
|
||||||
|
\\"text\\": \\"******\\",
|
||||||
|
\\"isChecked\\": false,
|
||||||
|
\\"id\\": 18
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
\\"type\\": 3,
|
||||||
|
\\"data\\": {
|
||||||
|
\\"source\\": 2,
|
||||||
|
\\"type\\": 1,
|
||||||
|
\\"id\\": 20
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
\\"type\\": 3,
|
||||||
|
\\"data\\": {
|
||||||
|
\\"source\\": 2,
|
||||||
|
\\"type\\": 6,
|
||||||
|
\\"id\\": 18
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
\\"type\\": 3,
|
||||||
|
\\"data\\": {
|
||||||
|
\\"source\\": 2,
|
||||||
|
\\"type\\": 5,
|
||||||
|
\\"id\\": 20
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
\\"type\\": 3,
|
||||||
|
\\"data\\": {
|
||||||
|
\\"source\\": 2,
|
||||||
|
\\"type\\": 0,
|
||||||
|
\\"id\\": 20
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
\\"type\\": 3,
|
||||||
|
\\"data\\": {
|
||||||
|
\\"source\\": 2,
|
||||||
|
\\"type\\": 2,
|
||||||
|
\\"id\\": 20
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
\\"type\\": 3,
|
||||||
|
\\"data\\": {
|
||||||
|
\\"source\\": 0,
|
||||||
|
\\"texts\\": [],
|
||||||
|
\\"attributes\\": [
|
||||||
|
{
|
||||||
|
\\"id\\": 18,
|
||||||
|
\\"attributes\\": {
|
||||||
|
\\"type\\": \\"text\\"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
\\"removes\\": [],
|
||||||
|
\\"adds\\": []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
\\"type\\": 3,
|
||||||
|
\\"data\\": {
|
||||||
|
\\"source\\": 0,
|
||||||
|
\\"texts\\": [],
|
||||||
|
\\"attributes\\": [
|
||||||
|
{
|
||||||
|
\\"id\\": 18,
|
||||||
|
\\"attributes\\": {
|
||||||
|
\\"data-rr-is-password\\": \\"true\\"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
\\"removes\\": [],
|
||||||
|
\\"adds\\": []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
\\"type\\": 3,
|
||||||
|
\\"data\\": {
|
||||||
|
\\"source\\": 2,
|
||||||
|
\\"type\\": 6,
|
||||||
|
\\"id\\": 20
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
\\"type\\": 3,
|
||||||
|
\\"data\\": {
|
||||||
|
\\"source\\": 2,
|
||||||
|
\\"type\\": 5,
|
||||||
|
\\"id\\": 18
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
\\"type\\": 3,
|
||||||
|
\\"data\\": {
|
||||||
|
\\"source\\": 5,
|
||||||
|
\\"text\\": \\"*******\\",
|
||||||
|
\\"isChecked\\": false,
|
||||||
|
\\"id\\": 18
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
\\"type\\": 3,
|
||||||
|
\\"data\\": {
|
||||||
|
\\"source\\": 5,
|
||||||
|
\\"text\\": \\"********\\",
|
||||||
|
\\"isChecked\\": false,
|
||||||
|
\\"id\\": 18
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
\\"type\\": 3,
|
||||||
|
\\"data\\": {
|
||||||
|
\\"source\\": 2,
|
||||||
|
\\"type\\": 1,
|
||||||
|
\\"id\\": 20
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
\\"type\\": 3,
|
||||||
|
\\"data\\": {
|
||||||
|
\\"source\\": 2,
|
||||||
|
\\"type\\": 6,
|
||||||
|
\\"id\\": 18
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
\\"type\\": 3,
|
||||||
|
\\"data\\": {
|
||||||
|
\\"source\\": 2,
|
||||||
|
\\"type\\": 5,
|
||||||
|
\\"id\\": 20
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
\\"type\\": 3,
|
||||||
|
\\"data\\": {
|
||||||
|
\\"source\\": 2,
|
||||||
|
\\"type\\": 0,
|
||||||
|
\\"id\\": 20
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
\\"type\\": 3,
|
||||||
|
\\"data\\": {
|
||||||
|
\\"source\\": 2,
|
||||||
|
\\"type\\": 2,
|
||||||
|
\\"id\\": 20
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
\\"type\\": 3,
|
||||||
|
\\"data\\": {
|
||||||
|
\\"source\\": 0,
|
||||||
|
\\"texts\\": [],
|
||||||
|
\\"attributes\\": [
|
||||||
|
{
|
||||||
|
\\"id\\": 18,
|
||||||
|
\\"attributes\\": {
|
||||||
|
\\"type\\": \\"password\\"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
\\"removes\\": [],
|
||||||
|
\\"adds\\": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]"
|
||||||
|
`;
|
||||||
|
|
||||||
exports[`record integration tests should mask texts 1`] = `
|
exports[`record integration tests should mask texts 1`] = `
|
||||||
"[
|
"[
|
||||||
{
|
{
|
||||||
@@ -5658,367 +6103,6 @@ exports[`record integration tests should mask texts using maskTextFn 1`] = `
|
|||||||
]"
|
]"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`record integration tests should mask value attribute with maskInputOptions 1`] = `
|
|
||||||
"[
|
|
||||||
{
|
|
||||||
\\"type\\": 0,
|
|
||||||
\\"data\\": {}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
\\"type\\": 1,
|
|
||||||
\\"data\\": {}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
\\"type\\": 4,
|
|
||||||
\\"data\\": {
|
|
||||||
\\"href\\": \\"about:blank\\",
|
|
||||||
\\"width\\": 1920,
|
|
||||||
\\"height\\": 1080
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
\\"type\\": 2,
|
|
||||||
\\"data\\": {
|
|
||||||
\\"node\\": {
|
|
||||||
\\"type\\": 0,
|
|
||||||
\\"childNodes\\": [
|
|
||||||
{
|
|
||||||
\\"type\\": 1,
|
|
||||||
\\"name\\": \\"html\\",
|
|
||||||
\\"publicId\\": \\"\\",
|
|
||||||
\\"systemId\\": \\"\\",
|
|
||||||
\\"id\\": 2
|
|
||||||
},
|
|
||||||
{
|
|
||||||
\\"type\\": 2,
|
|
||||||
\\"tagName\\": \\"html\\",
|
|
||||||
\\"attributes\\": {
|
|
||||||
\\"lang\\": \\"en\\"
|
|
||||||
},
|
|
||||||
\\"childNodes\\": [
|
|
||||||
{
|
|
||||||
\\"type\\": 2,
|
|
||||||
\\"tagName\\": \\"head\\",
|
|
||||||
\\"attributes\\": {},
|
|
||||||
\\"childNodes\\": [
|
|
||||||
{
|
|
||||||
\\"type\\": 3,
|
|
||||||
\\"textContent\\": \\"\\\\n \\",
|
|
||||||
\\"id\\": 5
|
|
||||||
},
|
|
||||||
{
|
|
||||||
\\"type\\": 2,
|
|
||||||
\\"tagName\\": \\"meta\\",
|
|
||||||
\\"attributes\\": {
|
|
||||||
\\"charset\\": \\"UTF-8\\"
|
|
||||||
},
|
|
||||||
\\"childNodes\\": [],
|
|
||||||
\\"id\\": 6
|
|
||||||
},
|
|
||||||
{
|
|
||||||
\\"type\\": 3,
|
|
||||||
\\"textContent\\": \\"\\\\n \\",
|
|
||||||
\\"id\\": 7
|
|
||||||
},
|
|
||||||
{
|
|
||||||
\\"type\\": 2,
|
|
||||||
\\"tagName\\": \\"meta\\",
|
|
||||||
\\"attributes\\": {
|
|
||||||
\\"http-equiv\\": \\"X-UA-Compatible\\",
|
|
||||||
\\"content\\": \\"IE=edge\\"
|
|
||||||
},
|
|
||||||
\\"childNodes\\": [],
|
|
||||||
\\"id\\": 8
|
|
||||||
},
|
|
||||||
{
|
|
||||||
\\"type\\": 3,
|
|
||||||
\\"textContent\\": \\"\\\\n \\",
|
|
||||||
\\"id\\": 9
|
|
||||||
},
|
|
||||||
{
|
|
||||||
\\"type\\": 2,
|
|
||||||
\\"tagName\\": \\"meta\\",
|
|
||||||
\\"attributes\\": {
|
|
||||||
\\"name\\": \\"viewport\\",
|
|
||||||
\\"content\\": \\"width=device-width, initial-scale=1.0\\"
|
|
||||||
},
|
|
||||||
\\"childNodes\\": [],
|
|
||||||
\\"id\\": 10
|
|
||||||
},
|
|
||||||
{
|
|
||||||
\\"type\\": 3,
|
|
||||||
\\"textContent\\": \\"\\\\n \\",
|
|
||||||
\\"id\\": 11
|
|
||||||
},
|
|
||||||
{
|
|
||||||
\\"type\\": 2,
|
|
||||||
\\"tagName\\": \\"title\\",
|
|
||||||
\\"attributes\\": {},
|
|
||||||
\\"childNodes\\": [
|
|
||||||
{
|
|
||||||
\\"type\\": 3,
|
|
||||||
\\"textContent\\": \\"Document\\",
|
|
||||||
\\"id\\": 13
|
|
||||||
}
|
|
||||||
],
|
|
||||||
\\"id\\": 12
|
|
||||||
},
|
|
||||||
{
|
|
||||||
\\"type\\": 3,
|
|
||||||
\\"textContent\\": \\"\\\\n \\",
|
|
||||||
\\"id\\": 14
|
|
||||||
}
|
|
||||||
],
|
|
||||||
\\"id\\": 4
|
|
||||||
},
|
|
||||||
{
|
|
||||||
\\"type\\": 3,
|
|
||||||
\\"textContent\\": \\"\\\\n \\",
|
|
||||||
\\"id\\": 15
|
|
||||||
},
|
|
||||||
{
|
|
||||||
\\"type\\": 2,
|
|
||||||
\\"tagName\\": \\"body\\",
|
|
||||||
\\"attributes\\": {},
|
|
||||||
\\"childNodes\\": [
|
|
||||||
{
|
|
||||||
\\"type\\": 3,
|
|
||||||
\\"textContent\\": \\"\\\\n \\",
|
|
||||||
\\"id\\": 17
|
|
||||||
},
|
|
||||||
{
|
|
||||||
\\"type\\": 2,
|
|
||||||
\\"tagName\\": \\"input\\",
|
|
||||||
\\"attributes\\": {
|
|
||||||
\\"type\\": \\"password\\",
|
|
||||||
\\"id\\": \\"password\\"
|
|
||||||
},
|
|
||||||
\\"childNodes\\": [],
|
|
||||||
\\"id\\": 18
|
|
||||||
},
|
|
||||||
{
|
|
||||||
\\"type\\": 3,
|
|
||||||
\\"textContent\\": \\"\\\\n \\",
|
|
||||||
\\"id\\": 19
|
|
||||||
},
|
|
||||||
{
|
|
||||||
\\"type\\": 2,
|
|
||||||
\\"tagName\\": \\"script\\",
|
|
||||||
\\"attributes\\": {},
|
|
||||||
\\"childNodes\\": [
|
|
||||||
{
|
|
||||||
\\"type\\": 3,
|
|
||||||
\\"textContent\\": \\"SCRIPT_PLACEHOLDER\\",
|
|
||||||
\\"id\\": 21
|
|
||||||
}
|
|
||||||
],
|
|
||||||
\\"id\\": 20
|
|
||||||
},
|
|
||||||
{
|
|
||||||
\\"type\\": 3,
|
|
||||||
\\"textContent\\": \\"\\\\n \\\\n \\",
|
|
||||||
\\"id\\": 22
|
|
||||||
},
|
|
||||||
{
|
|
||||||
\\"type\\": 2,
|
|
||||||
\\"tagName\\": \\"script\\",
|
|
||||||
\\"attributes\\": {},
|
|
||||||
\\"childNodes\\": [
|
|
||||||
{
|
|
||||||
\\"type\\": 3,
|
|
||||||
\\"textContent\\": \\"SCRIPT_PLACEHOLDER\\",
|
|
||||||
\\"id\\": 24
|
|
||||||
}
|
|
||||||
],
|
|
||||||
\\"id\\": 23
|
|
||||||
},
|
|
||||||
{
|
|
||||||
\\"type\\": 3,
|
|
||||||
\\"textContent\\": \\"\\\\n \\\\n \\\\n\\\\n\\",
|
|
||||||
\\"id\\": 25
|
|
||||||
}
|
|
||||||
],
|
|
||||||
\\"id\\": 16
|
|
||||||
}
|
|
||||||
],
|
|
||||||
\\"id\\": 3
|
|
||||||
}
|
|
||||||
],
|
|
||||||
\\"id\\": 1
|
|
||||||
},
|
|
||||||
\\"initialOffset\\": {
|
|
||||||
\\"left\\": 0,
|
|
||||||
\\"top\\": 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
\\"type\\": 3,
|
|
||||||
\\"data\\": {
|
|
||||||
\\"source\\": 2,
|
|
||||||
\\"type\\": 5,
|
|
||||||
\\"id\\": 18
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
\\"type\\": 3,
|
|
||||||
\\"data\\": {
|
|
||||||
\\"source\\": 5,
|
|
||||||
\\"text\\": \\"*\\",
|
|
||||||
\\"isChecked\\": false,
|
|
||||||
\\"id\\": 18
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
\\"type\\": 3,
|
|
||||||
\\"data\\": {
|
|
||||||
\\"source\\": 0,
|
|
||||||
\\"texts\\": [],
|
|
||||||
\\"attributes\\": [
|
|
||||||
{
|
|
||||||
\\"id\\": 18,
|
|
||||||
\\"attributes\\": {
|
|
||||||
\\"value\\": \\"*\\"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
\\"removes\\": [],
|
|
||||||
\\"adds\\": []
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
\\"type\\": 3,
|
|
||||||
\\"data\\": {
|
|
||||||
\\"source\\": 5,
|
|
||||||
\\"text\\": \\"**\\",
|
|
||||||
\\"isChecked\\": false,
|
|
||||||
\\"id\\": 18
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
\\"type\\": 3,
|
|
||||||
\\"data\\": {
|
|
||||||
\\"source\\": 0,
|
|
||||||
\\"texts\\": [],
|
|
||||||
\\"attributes\\": [
|
|
||||||
{
|
|
||||||
\\"id\\": 18,
|
|
||||||
\\"attributes\\": {
|
|
||||||
\\"value\\": \\"**\\"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
\\"removes\\": [],
|
|
||||||
\\"adds\\": []
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
\\"type\\": 3,
|
|
||||||
\\"data\\": {
|
|
||||||
\\"source\\": 5,
|
|
||||||
\\"text\\": \\"***\\",
|
|
||||||
\\"isChecked\\": false,
|
|
||||||
\\"id\\": 18
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
\\"type\\": 3,
|
|
||||||
\\"data\\": {
|
|
||||||
\\"source\\": 0,
|
|
||||||
\\"texts\\": [],
|
|
||||||
\\"attributes\\": [
|
|
||||||
{
|
|
||||||
\\"id\\": 18,
|
|
||||||
\\"attributes\\": {
|
|
||||||
\\"value\\": \\"***\\"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
\\"removes\\": [],
|
|
||||||
\\"adds\\": []
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
\\"type\\": 3,
|
|
||||||
\\"data\\": {
|
|
||||||
\\"source\\": 5,
|
|
||||||
\\"text\\": \\"****\\",
|
|
||||||
\\"isChecked\\": false,
|
|
||||||
\\"id\\": 18
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
\\"type\\": 3,
|
|
||||||
\\"data\\": {
|
|
||||||
\\"source\\": 0,
|
|
||||||
\\"texts\\": [],
|
|
||||||
\\"attributes\\": [
|
|
||||||
{
|
|
||||||
\\"id\\": 18,
|
|
||||||
\\"attributes\\": {
|
|
||||||
\\"value\\": \\"****\\"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
\\"removes\\": [],
|
|
||||||
\\"adds\\": []
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
\\"type\\": 3,
|
|
||||||
\\"data\\": {
|
|
||||||
\\"source\\": 5,
|
|
||||||
\\"text\\": \\"*****\\",
|
|
||||||
\\"isChecked\\": false,
|
|
||||||
\\"id\\": 18
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
\\"type\\": 3,
|
|
||||||
\\"data\\": {
|
|
||||||
\\"source\\": 0,
|
|
||||||
\\"texts\\": [],
|
|
||||||
\\"attributes\\": [
|
|
||||||
{
|
|
||||||
\\"id\\": 18,
|
|
||||||
\\"attributes\\": {
|
|
||||||
\\"value\\": \\"*****\\"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
\\"removes\\": [],
|
|
||||||
\\"adds\\": []
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
\\"type\\": 3,
|
|
||||||
\\"data\\": {
|
|
||||||
\\"source\\": 5,
|
|
||||||
\\"text\\": \\"******\\",
|
|
||||||
\\"isChecked\\": false,
|
|
||||||
\\"id\\": 18
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
\\"type\\": 3,
|
|
||||||
\\"data\\": {
|
|
||||||
\\"source\\": 0,
|
|
||||||
\\"texts\\": [],
|
|
||||||
\\"attributes\\": [
|
|
||||||
{
|
|
||||||
\\"id\\": 18,
|
|
||||||
\\"attributes\\": {
|
|
||||||
\\"value\\": \\"******\\"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
\\"removes\\": [],
|
|
||||||
\\"adds\\": []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]"
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`record integration tests should nest record iframe 1`] = `
|
exports[`record integration tests should nest record iframe 1`] = `
|
||||||
"[
|
"[
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -8,11 +8,13 @@
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<input type="password" id="password" />
|
<input type="password" id="password" />
|
||||||
|
<button type="button" id="show-password">Toggle show password</button>
|
||||||
<script>
|
<script>
|
||||||
const password = document.getElementById('password');
|
const password = document.getElementById('password');
|
||||||
password.addEventListener('keyup', (event) => {
|
|
||||||
password.setAttribute('value', password.value);
|
document.getElementById('show-password').addEventListener('click', function() {
|
||||||
|
password.setAttribute('type', password.getAttribute('type') === 'password' ? 'text' : 'password');
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -281,7 +281,7 @@ describe('record integration tests', function (this: ISuite) {
|
|||||||
assertSnapshot(snapshots);
|
assertSnapshot(snapshots);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should mask value attribute with maskInputOptions', async () => {
|
it('should mask password value attribute with maskInputOptions', async () => {
|
||||||
const page: puppeteer.Page = await browser.newPage();
|
const page: puppeteer.Page = await browser.newPage();
|
||||||
await page.goto('about:blank');
|
await page.goto('about:blank');
|
||||||
await page.setContent(
|
await page.setContent(
|
||||||
@@ -292,7 +292,12 @@ describe('record integration tests', function (this: ISuite) {
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
await page.type('input[type="password"]', 'secr3t');
|
await page.type('#password', 'secr3t');
|
||||||
|
|
||||||
|
// Change type to text (simulate "show password")
|
||||||
|
await page.click('#show-password');
|
||||||
|
await page.type('#password', 'XY');
|
||||||
|
await page.click('#show-password');
|
||||||
|
|
||||||
const snapshots = (await page.evaluate(
|
const snapshots = (await page.evaluate(
|
||||||
'window.snapshots',
|
'window.snapshots',
|
||||||
|
|||||||
Reference in New Issue
Block a user