Skip to content

Commit

Permalink
πŸ›[RUM-2752] Replay: generate censored images with custom dimensions (#…
Browse files Browse the repository at this point in the history
…2565)

* Replay: generate censored image with similar dimension than the original

* πŸ‘Œ add extra fallback
  • Loading branch information
bcaudan authored Jan 16, 2024
1 parent fe9fb03 commit 152e358
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -119,3 +119,7 @@ export function getValidTagName(tagName: string): string {

return processedTagName
}

export function censoredImageForSize(width: number, height: number) {
return `data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='${width}' height='${height}' style='background-color:silver'%3E%3C/svg%3E`
}
Original file line number Diff line number Diff line change
Expand Up @@ -96,4 +96,46 @@ describe('serializeAttribute', () => {
expect(serializeAttribute(node, NodePrivacyLevel.MASK, STABLE_ATTRIBUTES[0], DEFAULT_CONFIGURATION)).toBe('foo')
})
})

describe('image masking', () => {
let imageStub: Partial<Element> & { width: number; height: number; naturalWidth: number; naturalHeight: number }

beforeEach(() => {
imageStub = {
width: 0,
height: 0,
naturalWidth: 0,
naturalHeight: 0,
tagName: 'IMG',
getAttribute() {
return 'http://foo.bar/image.png'
},
getBoundingClientRect() {
return { width: this.width, height: this.height } as DOMRect
},
}
})

it('should use an image with same natural dimension than the original one', () => {
imageStub.naturalWidth = 2000
imageStub.naturalHeight = 1000
expect(serializeAttribute(imageStub as Element, NodePrivacyLevel.MASK, 'src', DEFAULT_CONFIGURATION)).toBe(
"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='2000' height='1000' style='background-color:silver'%3E%3C/svg%3E"
)
})

it('should use an image with same rendering dimension than the original one', () => {
imageStub.width = 200
imageStub.height = 100
expect(serializeAttribute(imageStub as Element, NodePrivacyLevel.MASK, 'src', DEFAULT_CONFIGURATION)).toBe(
"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='100' style='background-color:silver'%3E%3C/svg%3E"
)
})

it("should use the censored image when original image size can't be computed", () => {
expect(serializeAttribute(imageStub as Element, NodePrivacyLevel.MASK, 'src', DEFAULT_CONFIGURATION)).toBe(
'data:image/gif;base64,R0lGODlhAQABAIAAAMLCwgAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw=='
)
})
})
})
22 changes: 19 additions & 3 deletions packages/rum/src/domain/record/serialization/serializeAttribute.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { STABLE_ATTRIBUTES } from '@datadog/browser-rum-core'
import type { RumConfiguration } from '@datadog/browser-rum-core'
import { NodePrivacyLevel, PRIVACY_ATTR_NAME, CENSORED_STRING_MARK, CENSORED_IMG_MARK } from '../../../constants'
import { MAX_ATTRIBUTE_VALUE_CHAR_LENGTH } from '../privacy'
import { censoredImageForSize } from './serializationUtils'

export function serializeAttribute(
element: Element,
Expand Down Expand Up @@ -30,12 +31,27 @@ export function serializeAttribute(
case 'placeholder':
return CENSORED_STRING_MARK
}

// mask image URLs
if (tagName === 'IMG' || tagName === 'SOURCE') {
if (attributeName === 'src' || attributeName === 'srcset') {
return CENSORED_IMG_MARK
if (tagName === 'IMG' && (attributeName === 'src' || attributeName === 'srcset')) {
// generate image with similar dimension than the original to have the same rendering behaviour
const image = element as HTMLImageElement
if (image.naturalWidth > 0) {
return censoredImageForSize(image.naturalWidth, image.naturalHeight)
}
const { width, height } = element.getBoundingClientRect()
if (width > 0 || height > 0) {
return censoredImageForSize(width, height)
}
// if we can't get the image size, fallback to the censored image
return CENSORED_IMG_MARK
}

// mask source URLs
if (tagName === 'SOURCE' && (attributeName === 'src' || attributeName === 'srcset')) {
return CENSORED_IMG_MARK
}

// mask <a> URLs
if (tagName === 'A' && attributeName === 'href') {
return CENSORED_STRING_MARK
Expand Down

0 comments on commit 152e358

Please sign in to comment.