import type { RumConfiguration } from '@openobserve/browser-rum-core' import { NodePrivacyLevel, PRIVACY_ATTR_NAME } from '@openobserve/browser-rum-core' import { display, noop, objectValues } from '@openobserve/browser-core' import type { SerializedNodeWithId } from '../../../types' import { serializeNodeWithId, SerializationContextStatus, createElementsScrollPositions, createSerializationStats, } from '..' import { createNodeIds } from '../nodeIds' import { createSerializationScope } from './serializationScope' export const makeHtmlDoc = (htmlContent: string, privacyTag: string) => { try { const newDoc = document.implementation.createHTMLDocument('new doc') newDoc.documentElement.innerHTML = htmlContent newDoc.documentElement.setAttribute(PRIVACY_ATTR_NAME, privacyTag) return newDoc } catch (e) { display.error('Failed to set innerHTML of new doc:', e) return document } } export const removeIdFieldsRecursivelyClone = (thing: Record): Record => { if (thing && typeof thing === 'object') { const object = thing delete object.id objectValues(object).forEach((value) => removeIdFieldsRecursivelyClone(value as Record)) return object } return thing } const DEFAULT_SHADOW_ROOT_CONTROLLER = { flush: noop, stop: noop, addShadowRoot: noop, removeShadowRoot: noop, } export const generateLeanSerializedDoc = (htmlContent: string, privacyTag: string) => { const newDoc = makeHtmlDoc(htmlContent, privacyTag) const serializedDoc = removeIdFieldsRecursivelyClone( serializeNodeWithId(newDoc, NodePrivacyLevel.ALLOW, { serializationContext: { serializationStats: createSerializationStats(), shadowRootsController: DEFAULT_SHADOW_ROOT_CONTROLLER, status: SerializationContextStatus.INITIAL_FULL_SNAPSHOT, elementsScrollPositions: createElementsScrollPositions(), }, configuration: {} as RumConfiguration, scope: createSerializationScope(createNodeIds()), })! as unknown as Record ) as unknown as SerializedNodeWithId return serializedDoc } export const HTML = ` private title

hello private world

Loreum ipsum private text

Click https://private.com/path/nested?query=param#hash
editable private div
` export const AST_HIDDEN = { type: 0, childNodes: [ { type: 1, name: 'html', publicId: '', systemId: '', }, { type: 2, tagName: 'html', attributes: { rr_width: '0px', rr_height: '0px', 'data-oo-privacy': 'hidden', }, childNodes: [], }, ], } export const AST_MASK = { type: 0, childNodes: [ { type: 1, name: 'html', publicId: '', systemId: '', }, { type: 2, tagName: 'html', attributes: { 'data-oo-privacy': 'mask', }, childNodes: [ { type: 2, tagName: 'head', attributes: {}, childNodes: [ { type: 2, tagName: 'link', attributes: { href: 'https://public.com/path/nested?query=param#hash', rel: 'stylesheet', }, childNodes: [], }, { type: 2, tagName: 'style', attributes: { _cssText: '.example { color: red; }' }, childNodes: [], }, { type: 2, tagName: 'meta', attributes: {}, childNodes: [], }, { type: 2, tagName: 'base', attributes: {}, childNodes: [], }, { type: 2, tagName: 'title', attributes: {}, childNodes: [ { type: 3, textContent: 'xxxxxxx xxxxx', }, ], }, ], }, { type: 3, textContent: '\n', }, { type: 2, tagName: 'body', attributes: {}, childNodes: [ { type: 3, textContent: '\n ', }, { type: 2, tagName: 'h1', attributes: {}, childNodes: [ { type: 3, textContent: 'xxxxx xxxxxxx xxxxx', }, ], }, { type: 3, textContent: '\n ', }, { type: 2, tagName: 'p', attributes: {}, childNodes: [ { type: 3, textContent: 'xxxxxx xxxxx xxxxxxx xxxx', }, ], }, { type: 3, textContent: '\n ', }, { type: 2, tagName: 'noscript', attributes: {}, childNodes: [ { type: 3, textContent: 'xxxxx xxxxxxx xxxxx', }, ], }, { type: 3, textContent: '\n ', }, { type: 2, tagName: 'a', attributes: { href: '***', }, childNodes: [ { type: 3, textContent: '\n xxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n ', }, ], }, { type: 3, textContent: '\n ', }, { type: 2, tagName: 'img', attributes: { src: 'data:image/gif;base64,R0lGODlhAQABAIAAAMLCwgAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==', }, childNodes: [], }, { type: 3, textContent: '\n ', }, { type: 2, tagName: 'video', attributes: { controls: '', rr_mediaState: 'paused', }, childNodes: [ { type: 3, textContent: '\n ', }, { type: 2, tagName: 'source', attributes: { src: 'data:image/gif;base64,R0lGODlhAQABAIAAAMLCwgAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==', type: 'video/webm', }, childNodes: [], }, { type: 3, textContent: '\n ', }, { type: 2, tagName: 'source', attributes: { src: 'data:image/gif;base64,R0lGODlhAQABAIAAAMLCwgAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==', type: 'video/mp4', }, childNodes: [], }, { type: 3, textContent: '\n ', }, { type: 2, tagName: 'p', attributes: {}, childNodes: [ { type: 3, textContent: 'xxxx xxxxxxx xxxxxx xxxx xxx xxxxxxxx xxxxx xxxxx', }, ], }, { type: 3, textContent: '\n ', }, ], }, { type: 3, textContent: '\n ', }, { type: 2, tagName: 'select', attributes: { value: '***', }, childNodes: [ { type: 2, tagName: 'option', attributes: {}, childNodes: [ { type: 3, textContent: '***', }, ], }, { type: 2, tagName: 'option', attributes: {}, childNodes: [ { type: 3, textContent: '***', }, ], }, { type: 2, tagName: 'option', attributes: {}, childNodes: [ { type: 3, textContent: '***', }, ], }, ], }, { type: 3, textContent: '\n ', }, { type: 2, tagName: 'input', attributes: { type: 'password', }, childNodes: [], }, { type: 3, textContent: '\n ', }, { type: 2, tagName: 'input', attributes: { type: 'text', }, childNodes: [], }, { type: 3, textContent: '\n ', }, { type: 2, tagName: 'input', attributes: { type: 'checkbox', name: 'inputFoo', value: '***', }, childNodes: [], }, { type: 3, textContent: '\n ', }, { type: 2, tagName: 'label', attributes: { for: 'inputFoo', }, childNodes: [ { type: 3, textContent: 'xxxxxxxx xxxxx', }, ], }, { type: 3, textContent: '\n\n ', }, { type: 2, tagName: 'input', attributes: { type: 'radio', name: 'radioGroup', value: '***', }, childNodes: [], }, { type: 3, textContent: '\n\n ', }, { type: 2, tagName: 'textarea', attributes: { name: 'baz', rows: '2', cols: '20', value: '***', }, childNodes: [ { type: 3, textContent: ' xxxxxx xxxxx xxxxxxx xxx\n ', }, ], }, { type: 3, textContent: '\n\n ', }, { type: 2, tagName: 'div', attributes: { contenteditable: '', }, childNodes: [ { type: 3, textContent: 'xxxxxxxx xxxxxxx xxx', }, ], }, { type: 3, textContent: '\n', }, ], }, ], }, ], } export const AST_MASK_USER_INPUT = { type: 0, childNodes: [ { type: 1, name: 'html', publicId: '', systemId: '', }, { type: 2, tagName: 'html', attributes: { 'data-oo-privacy': 'mask-user-input', }, childNodes: [ { type: 2, tagName: 'head', attributes: {}, childNodes: [ { type: 2, tagName: 'link', attributes: { href: 'https://public.com/path/nested?query=param#hash', rel: 'stylesheet', }, childNodes: [], }, { type: 2, tagName: 'style', attributes: { _cssText: '.example { color: red; }' }, childNodes: [], }, { type: 2, tagName: 'meta', attributes: {}, childNodes: [], }, { type: 2, tagName: 'base', attributes: {}, childNodes: [], }, { type: 2, tagName: 'title', attributes: {}, childNodes: [ { type: 3, textContent: 'private title', }, ], }, ], }, { type: 3, textContent: '\n', }, { type: 2, tagName: 'body', attributes: {}, childNodes: [ { type: 3, textContent: '\n ', }, { type: 2, tagName: 'h1', attributes: {}, childNodes: [ { type: 3, textContent: 'hello private world', }, ], }, { type: 3, textContent: '\n ', }, { type: 2, tagName: 'p', attributes: {}, childNodes: [ { type: 3, textContent: 'Loreum ipsum private text', }, ], }, { type: 3, textContent: '\n ', }, { type: 2, tagName: 'noscript', attributes: {}, childNodes: [ { type: 3, textContent: 'hello private world', }, ], }, { type: 3, textContent: '\n ', }, { type: 2, tagName: 'a', attributes: { href: 'https://private.com/path/nested?query=param#hash', }, childNodes: [ { type: 3, textContent: '\n Click https://private.com/path/nested?query=param#hash\n ', }, ], }, { type: 3, textContent: '\n ', }, { type: 2, tagName: 'img', attributes: { src: 'https://private.com/path/nested?query=param#hash', }, childNodes: [], }, { type: 3, textContent: '\n ', }, { type: 2, tagName: 'video', attributes: { controls: '', rr_mediaState: 'paused', }, childNodes: [ { type: 3, textContent: '\n ', }, { type: 2, tagName: 'source', attributes: { src: 'https://private.com/path/nested?query=param#hash', type: 'video/webm', }, childNodes: [], }, { type: 3, textContent: '\n ', }, { type: 2, tagName: 'source', attributes: { src: 'https://private.com/path/nested?query=param#hash', type: 'video/mp4', }, childNodes: [], }, { type: 3, textContent: '\n ', }, { type: 2, tagName: 'p', attributes: {}, childNodes: [ { type: 3, textContent: 'Your browser cannot play the provided video file.', }, ], }, { type: 3, textContent: '\n ', }, ], }, { type: 3, textContent: '\n ', }, { type: 2, tagName: 'select', attributes: { value: '***', }, childNodes: [ { type: 2, tagName: 'option', attributes: {}, childNodes: [ { type: 3, textContent: '***', }, ], }, { type: 2, tagName: 'option', attributes: {}, childNodes: [ { type: 3, textContent: '***', }, ], }, { type: 2, tagName: 'option', attributes: {}, childNodes: [ { type: 3, textContent: '***', }, ], }, ], }, { type: 3, textContent: '\n ', }, { type: 2, tagName: 'input', attributes: { type: 'password', }, childNodes: [], }, { type: 3, textContent: '\n ', }, { type: 2, tagName: 'input', attributes: { type: 'text', }, childNodes: [], }, { type: 3, textContent: '\n ', }, { type: 2, tagName: 'input', attributes: { type: 'checkbox', name: 'inputFoo', value: '***', }, childNodes: [], }, { type: 3, textContent: '\n ', }, { type: 2, tagName: 'label', attributes: { for: 'inputFoo', }, childNodes: [ { type: 3, textContent: 'inputFoo label', }, ], }, { type: 3, textContent: '\n\n ', }, { type: 2, tagName: 'input', attributes: { type: 'radio', name: 'radioGroup', value: '***', }, childNodes: [], }, { type: 3, textContent: '\n\n ', }, { type: 2, tagName: 'textarea', attributes: { name: 'baz', rows: '2', cols: '20', value: '***', }, childNodes: [ { type: 3, textContent: ' xxxxxx xxxxx xxxxxxx xxx\n ', }, ], }, { type: 3, textContent: '\n\n ', }, { type: 2, tagName: 'div', attributes: { contenteditable: '', }, childNodes: [ { type: 3, textContent: 'editable private div', }, ], }, { type: 3, textContent: '\n', }, ], }, ], }, ], } export const AST_MASK_UNLESS_ALLOWLISTED = { type: 0, childNodes: [ { type: 1, name: 'html', publicId: '', systemId: '', }, { type: 2, tagName: 'html', attributes: { 'data-dd-privacy': 'mask-unless-allowlisted', }, childNodes: [ { type: 2, tagName: 'head', attributes: {}, childNodes: [ { type: 2, tagName: 'link', attributes: { href: 'https://public.com/path/nested?query=param#hash', rel: 'stylesheet', }, childNodes: [], }, { type: 2, tagName: 'style', attributes: { _cssText: '.example { color: red; }' }, childNodes: [], }, { type: 2, tagName: 'meta', attributes: {}, childNodes: [], }, { type: 2, tagName: 'base', attributes: {}, childNodes: [], }, { type: 2, tagName: 'title', attributes: {}, childNodes: [ { type: 3, textContent: 'xxxxxxx xxxxx', }, ], }, ], }, { type: 3, textContent: '\n', }, { type: 2, tagName: 'body', attributes: {}, childNodes: [ { type: 3, textContent: '\n ', }, { type: 2, tagName: 'h1', attributes: {}, childNodes: [ { type: 3, textContent: 'xxxxx xxxxxxx xxxxx', }, ], }, { type: 3, textContent: '\n ', }, { type: 2, tagName: 'p', attributes: {}, childNodes: [ { type: 3, textContent: 'xxxxxx xxxxx xxxxxxx xxxx', }, ], }, { type: 3, textContent: '\n ', }, { type: 2, tagName: 'noscript', attributes: {}, childNodes: [ { type: 3, textContent: 'xxxxx xxxxxxx xxxxx', }, ], }, { type: 3, textContent: '\n ', }, { type: 2, tagName: 'a', attributes: { href: '***', }, childNodes: [ { type: 3, textContent: '\n xxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n ', }, ], }, { type: 3, textContent: '\n ', }, { type: 2, tagName: 'img', attributes: { src: 'data:image/gif;base64,R0lGODlhAQABAIAAAMLCwgAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==', }, childNodes: [], }, { type: 3, textContent: '\n ', }, { type: 2, tagName: 'video', attributes: { controls: '', rr_mediaState: 'paused', }, childNodes: [ { type: 3, textContent: '\n ', }, { type: 2, tagName: 'source', attributes: { src: 'data:image/gif;base64,R0lGODlhAQABAIAAAMLCwgAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==', type: 'video/webm', }, childNodes: [], }, { type: 3, textContent: '\n ', }, { type: 2, tagName: 'source', attributes: { src: 'data:image/gif;base64,R0lGODlhAQABAIAAAMLCwgAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==', type: 'video/mp4', }, childNodes: [], }, { type: 3, textContent: '\n ', }, { type: 2, tagName: 'p', attributes: {}, childNodes: [ { type: 3, textContent: 'xxxx xxxxxxx xxxxxx xxxx xxx xxxxxxxx xxxxx xxxxx', }, ], }, { type: 3, textContent: '\n ', }, ], }, { type: 3, textContent: '\n ', }, { type: 2, tagName: 'select', attributes: { value: '***', }, childNodes: [ { type: 2, tagName: 'option', attributes: {}, childNodes: [ { type: 3, textContent: '***', }, ], }, { type: 2, tagName: 'option', attributes: {}, childNodes: [ { type: 3, textContent: '***', }, ], }, { type: 2, tagName: 'option', attributes: {}, childNodes: [ { type: 3, textContent: '***', }, ], }, ], }, { type: 3, textContent: '\n ', }, { type: 2, tagName: 'input', attributes: { type: 'password', }, childNodes: [], }, { type: 3, textContent: '\n ', }, { type: 2, tagName: 'input', attributes: { type: 'text', }, childNodes: [], }, { type: 3, textContent: '\n ', }, { type: 2, tagName: 'input', attributes: { type: 'checkbox', name: 'inputFoo', value: '***', }, childNodes: [], }, { type: 3, textContent: '\n ', }, { type: 2, tagName: 'label', attributes: { for: 'inputFoo', }, childNodes: [ { type: 3, textContent: 'xxxxxxxx xxxxx', }, ], }, { type: 3, textContent: '\n\n ', }, { type: 2, tagName: 'input', attributes: { type: 'radio', name: 'radioGroup', value: '***', }, childNodes: [], }, { type: 3, textContent: '\n\n ', }, { type: 2, tagName: 'textarea', attributes: { name: 'baz', rows: '2', cols: '20', value: '***', }, childNodes: [ { type: 3, textContent: ' xxxxxx xxxxx xxxxxxx xxx\n ', }, ], }, { type: 3, textContent: '\n\n ', }, { type: 2, tagName: 'div', attributes: { contenteditable: '', }, childNodes: [ { type: 3, textContent: 'xxxxxxxx xxxxxxx xxx', }, ], }, { type: 3, textContent: '\n', }, ], }, ], }, ], } export const AST_ALLOW = { type: 0, childNodes: [ { type: 1, name: 'html', publicId: '', systemId: '', }, { type: 2, tagName: 'html', attributes: { 'data-oo-privacy': 'allow', }, childNodes: [ { type: 2, tagName: 'head', attributes: {}, childNodes: [ { type: 2, tagName: 'link', attributes: { href: 'https://public.com/path/nested?query=param#hash', rel: 'stylesheet', }, childNodes: [], }, { type: 2, tagName: 'style', attributes: { _cssText: '.example { color: red; }' }, childNodes: [], }, { type: 2, tagName: 'meta', attributes: {}, childNodes: [], }, { type: 2, tagName: 'base', attributes: {}, childNodes: [], }, { type: 2, tagName: 'title', attributes: {}, childNodes: [ { type: 3, textContent: 'private title', }, ], }, ], }, { type: 3, textContent: '\n', }, { type: 2, tagName: 'body', attributes: {}, childNodes: [ { type: 3, textContent: '\n ', }, { type: 2, tagName: 'h1', attributes: {}, childNodes: [ { type: 3, textContent: 'hello private world', }, ], }, { type: 3, textContent: '\n ', }, { type: 2, tagName: 'p', attributes: {}, childNodes: [ { type: 3, textContent: 'Loreum ipsum private text', }, ], }, { type: 3, textContent: '\n ', }, { type: 2, tagName: 'noscript', attributes: {}, childNodes: [ { type: 3, textContent: 'hello private world', }, ], }, { type: 3, textContent: '\n ', }, { type: 2, tagName: 'a', attributes: { href: 'https://private.com/path/nested?query=param#hash', }, childNodes: [ { type: 3, textContent: '\n Click https://private.com/path/nested?query=param#hash\n ', }, ], }, { type: 3, textContent: '\n ', }, { type: 2, tagName: 'img', attributes: { src: 'https://private.com/path/nested?query=param#hash', }, childNodes: [], }, { type: 3, textContent: '\n ', }, { type: 2, tagName: 'video', attributes: { controls: '', rr_mediaState: 'paused', }, childNodes: [ { type: 3, textContent: '\n ', }, { type: 2, tagName: 'source', attributes: { src: 'https://private.com/path/nested?query=param#hash', type: 'video/webm', }, childNodes: [], }, { type: 3, textContent: '\n ', }, { type: 2, tagName: 'source', attributes: { src: 'https://private.com/path/nested?query=param#hash', type: 'video/mp4', }, childNodes: [], }, { type: 3, textContent: '\n ', }, { type: 2, tagName: 'p', attributes: {}, childNodes: [ { type: 3, textContent: 'Your browser cannot play the provided video file.', }, ], }, { type: 3, textContent: '\n ', }, ], }, { type: 3, textContent: '\n ', }, { type: 2, tagName: 'select', attributes: { value: 'private option A', }, childNodes: [ { type: 3, textContent: '\n ', }, { type: 2, tagName: 'option', attributes: { selected: true, value: 'private option A', }, childNodes: [ { type: 3, textContent: 'private option A', }, ], }, { type: 3, textContent: '\n ', }, { type: 2, tagName: 'option', attributes: { value: 'private option B', }, childNodes: [ { type: 3, textContent: 'private option B', }, ], }, { type: 3, textContent: '\n ', }, { type: 2, tagName: 'option', attributes: { value: 'private option C', }, childNodes: [ { type: 3, textContent: 'private option C', }, ], }, { type: 3, textContent: '\n ', }, ], }, { type: 3, textContent: '\n ', }, { type: 2, tagName: 'input', attributes: { type: 'password', }, childNodes: [], }, { type: 3, textContent: '\n ', }, { type: 2, tagName: 'input', attributes: { type: 'text', }, childNodes: [], }, { type: 3, textContent: '\n ', }, { type: 2, tagName: 'input', attributes: { type: 'checkbox', name: 'inputFoo', value: 'on', checked: true, }, childNodes: [], }, { type: 3, textContent: '\n ', }, { type: 2, tagName: 'label', attributes: { for: 'inputFoo', }, childNodes: [ { type: 3, textContent: 'inputFoo label', }, ], }, { type: 3, textContent: '\n\n ', }, { type: 2, tagName: 'input', attributes: { type: 'radio', name: 'radioGroup', value: 'bar-private', checked: false, }, childNodes: [], }, { type: 3, textContent: '\n\n ', }, { type: 2, tagName: 'textarea', attributes: { name: 'baz', rows: '2', cols: '20', value: ' Loreum Ipsum private ...\n ', }, childNodes: [ { type: 3, textContent: ' Loreum Ipsum private ...\n ', }, ], }, { type: 3, textContent: '\n\n ', }, { type: 2, tagName: 'div', attributes: { contenteditable: '', }, childNodes: [ { type: 3, textContent: 'editable private div', }, ], }, { type: 3, textContent: '\n', }, ], }, ], }, ], }