Skip to content

Commit

Permalink
Don't render SVG nodes if it taints canvas
Browse files Browse the repository at this point in the history
  • Loading branch information
niklasvh committed Aug 13, 2017
1 parent c765e20 commit 37a9249
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 10 deletions.
21 changes: 21 additions & 0 deletions src/Feature.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,34 @@ const testRangeBounds = document => {
return false;
};

const testSVG = document => {
const img = new Image();
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
img.src = `data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg'></svg>`;

try {
ctx.drawImage(img, 0, 0);
canvas.toDataURL();
} catch (e) {
return false;
}
return true;
};

const FEATURES = {
// $FlowFixMe - get/set properties not yet supported
get SUPPORT_RANGE_BOUNDS() {
'use strict';
const value = testRangeBounds(document);
Object.defineProperty(FEATURES, 'SUPPORT_RANGE_BOUNDS', {value});
return value;
},
get SUPPORT_SVG_DRAWING() {
'use strict';
const value = testSVG(document);
Object.defineProperty(FEATURES, 'SUPPORT_SVG_DRAWING', {value});
return value;
}
};

Expand Down
32 changes: 24 additions & 8 deletions src/ImageLoader.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import type Logger from './Logger';
export type ImageElement = Image | HTMLCanvasElement;
type ImageCache = {[string]: Promise<?ImageElement>};

import FEATURES from './Feature';

export default class ImageLoader {
origin: string;
options: Options;
Expand All @@ -30,10 +32,20 @@ export default class ImageLoader {
return src;
}

if (this.options.allowTaint === true || this.isInlineImage(src) || this.isSameOrigin(src)) {
return this.addImage(src, src);
} else if (typeof this.options.proxy === 'string' && !this.isSameOrigin(src)) {
// TODO proxy
if (isSVG(src)) {
if (this.options.allowTaint === true || FEATURES.SUPPORT_SVG_DRAWING) {
return this.addImage(src, src);
}
} else {
if (
this.options.allowTaint === true ||
isInlineImage(src) ||
this.isSameOrigin(src)
) {
return this.addImage(src, src);
} else if (typeof this.options.proxy === 'string' && !this.isSameOrigin(src)) {
// TODO proxy
}
}
}

Expand All @@ -43,10 +55,6 @@ export default class ImageLoader {
return key;
}

isInlineImage(src: string): boolean {
return /data:image\/.*;base64,/i.test(src);
}

hasImageInCache(key: string): boolean {
return typeof this.cache[key] !== 'undefined';
}
Expand Down Expand Up @@ -112,3 +120,11 @@ export class ImageStore {
return index === -1 ? null : this._images[index];
}
}

const INLINE_SVG = /^data:image\/svg\+xml/i;
const INLINE_IMG = /^data:image\/.*;base64,/i;

const isInlineImage = (src: string): boolean => INLINE_IMG.test(src);

const isSVG = (src: string): boolean =>
src.substr(-3).toLowerCase() === 'svg' || INLINE_SVG.test(src);
4 changes: 2 additions & 2 deletions tests/testrunner.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import parseRefTest from '../scripts/parse-reftest';
import reftests from './reftests';
import querystring from 'querystring';

const DOWNLOAD_REFTESTS = true;
const DOWNLOAD_REFTESTS = false;
const query = querystring.parse(location.search.replace(/^\?/, ''));

const downloadResult = (filename, data) => {
Expand Down Expand Up @@ -126,7 +126,7 @@ const assertPath = (result, expected, desc) => {

const delta = 10;

if (REFTEST) {
if (REFTEST && query.refTest === 'true') {
const RESULTS = parseRefTest(result);
REFTEST.forEach(({action, line, ...args}, i) => {
const RESULT = RESULTS[i];
Expand Down

0 comments on commit 37a9249

Please sign in to comment.