diff --git a/src/dom/document-cloner.ts b/src/dom/document-cloner.ts index d2fd930..08faa29 100644 --- a/src/dom/document-cloner.ts +++ b/src/dom/document-cloner.ts @@ -13,7 +13,8 @@ import { isStyleElement, isSVGElementNode, isTextareaElement, - isTextNode + isTextNode, + isVideoElement } from './node-parser'; import {isIdentToken, nonFunctionArgSeparator} from '../css/syntax/parser'; import {TokenType} from '../css/syntax/tokenizer'; @@ -145,7 +146,9 @@ export class DocumentCloner { if (isCanvasElement(node)) { return this.createCanvasClone(node); } - + if (isVideoElement(node)) { + return this.createVideoClone(node); + } if (isStyleElement(node)) { return this.createStyleClone(node); } @@ -244,6 +247,32 @@ export class DocumentCloner { return clonedCanvas; } + createVideoClone(video: HTMLVideoElement): HTMLCanvasElement { + const canvas = video.ownerDocument.createElement('canvas'); + + canvas.width = video.offsetWidth; + canvas.height = video.offsetHeight; + const ctx = canvas.getContext('2d'); + + try { + if (ctx) { + ctx.drawImage(video, 0, 0, canvas.width, canvas.height); + if (!this.options.allowTaint) { + ctx.getImageData(0, 0, canvas.width, canvas.height); + } + } + return canvas; + } catch (e) { + this.context.logger.info(`Unable to clone video as it is tainted`, video); + } + + const blankCanvas = video.ownerDocument.createElement('canvas'); + + blankCanvas.width = video.offsetWidth; + blankCanvas.height = video.offsetHeight; + return blankCanvas; + } + appendChildNode(clone: HTMLElement | SVGElement, child: Node, copyStyles: boolean): void { if ( !isElementNode(child) || @@ -257,6 +286,23 @@ export class DocumentCloner { } } + cloneChildNodes(node: Element, clone: HTMLElement | SVGElement, copyStyles: boolean): void { + for ( + let child = node.shadowRoot ? node.shadowRoot.firstChild : node.firstChild; + child; + child = child.nextSibling + ) { + if (isElementNode(child) && isSlotElement(child) && typeof child.assignedNodes === 'function') { + const assignedNodes = child.assignedNodes() as ChildNode[]; + if (assignedNodes.length) { + assignedNodes.forEach((assignedNode) => this.appendChildNode(clone, assignedNode, copyStyles)); + } + } else { + this.appendChildNode(clone, child, copyStyles); + } + } + } + cloneNode(node: Node, copyStyles: boolean): Node { if (isTextNode(node)) { return document.createTextNode(node.data); @@ -290,19 +336,8 @@ export class DocumentCloner { copyStyles = true; } - for ( - let child = node.shadowRoot ? node.shadowRoot.firstChild : node.firstChild; - child; - child = child.nextSibling - ) { - if (isElementNode(child) && isSlotElement(child) && typeof child.assignedNodes === 'function') { - const assignedNodes = child.assignedNodes() as ChildNode[]; - if (assignedNodes.length) { - assignedNodes.forEach((assignedNode) => this.appendChildNode(clone, assignedNode, copyStyles)); - } - } else { - this.appendChildNode(clone, child, copyStyles); - } + if (!isVideoElement(node)) { + this.cloneChildNodes(node, clone, copyStyles); } if (before) { diff --git a/src/dom/node-parser.ts b/src/dom/node-parser.ts index 0bae313..5f38a24 100644 --- a/src/dom/node-parser.ts +++ b/src/dom/node-parser.ts @@ -124,6 +124,7 @@ export const isHTMLElement = (node: Element): node is HTMLHtmlElement => node.ta export const isSVGElement = (node: Element): node is SVGSVGElement => node.tagName === 'svg'; export const isBodyElement = (node: Element): node is HTMLBodyElement => node.tagName === 'BODY'; export const isCanvasElement = (node: Element): node is HTMLCanvasElement => node.tagName === 'CANVAS'; +export const isVideoElement = (node: Element): node is HTMLVideoElement => node.tagName === 'VIDEO'; export const isImageElement = (node: Element): node is HTMLImageElement => node.tagName === 'IMG'; export const isIFrameElement = (node: Element): node is HTMLIFrameElement => node.tagName === 'IFRAME'; export const isStyleElement = (node: Element): node is HTMLStyleElement => node.tagName === 'STYLE'; diff --git a/tests/assets/cc0-video.mp4 b/tests/assets/cc0-video.mp4 new file mode 100644 index 0000000..cd869bd Binary files /dev/null and b/tests/assets/cc0-video.mp4 differ diff --git a/tests/reftests/images/video.html b/tests/reftests/images/video.html new file mode 100644 index 0000000..d33f817 --- /dev/null +++ b/tests/reftests/images/video.html @@ -0,0 +1,20 @@ + + + + + Video tests + + + +

Same origin

+ +

Cross-origin (doesn't taint)

+ + +