Permalink
Browse files

Safe alternative to creating an image element from a blob.

RELNOTES[NEW]: Added a helper function that guarantees revoking the object url created from createObjectUrl when creating an Image element from a blob with MIME type image/.*.

Also whitelists use of createObjectUrl in goog.dom.safe with MANUALLY_REVIEWED

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=228530531
  • Loading branch information...
nreid260 committed Jan 9, 2019
1 parent 049aa75 commit 6eca8fcdad2969d12c394e6fdb5316cd87011383
Showing with 66 additions and 0 deletions.
  1. +29 −0 closure/goog/dom/safe.js
  2. +37 −0 closure/goog/dom/safe_test.js
@@ -729,3 +729,32 @@ goog.dom.safe.openInWindow = function(
opt_name ? goog.string.Const.unwrap(opt_name) : '', opt_specs,
opt_replace);
};


/**
* Safely creates an HTMLImageElement from a Blob.
*
* Example usage:
* goog.dom.safe.createImageFromBlob(blob);
* which is a safe alternative to
* image.src = createObjectUrl(blob)
* The latter can result in executing malicious same-origin scripts from a bad
* Blob.
* @param {!Blob} blob The blob to create the image from.
* @return {!HTMLImageElement} The image element created from the blob.
* @throws {!Error} If called with a Blob with a MIME type other than image/.*.
*/
goog.dom.safe.createImageFromBlob = function(blob) {
// Any image/* MIME type is accepted as safe.
if (!/^image\/.*/g.test(blob.type)) {
throw new Error(
'goog.dom.safe.createImageFromBlob only accepts MIME type image/.*.');
}
var objectUrl = window.URL.createObjectURL(blob);
var image = new Image();
image.onload = function() {
window.URL.revokeObjectURL(objectUrl);
};
image.src = objectUrl;
return image;
};
@@ -728,6 +728,43 @@ function testOpenInWindow() {
'openInWindow should return the created window', fakeWindow, retVal);
}

function testCreateImageFromBlob() {
// Skip unsupported test if IE9 or lower.
if (goog.userAgent.IE && !goog.userAgent.isVersionOrHigher('10')) {
return;
}
var blob = new Blob(['data'], {type: 'image/svg+xml'});
var fakeObjectUrl = 'blob:http://fakeurl.com';
var mockCreateObject = /** @type {?} */ (
goog.testing.createMethodMock(window.URL, 'createObjectURL'));
var mockRevokeObject = /** @type {?} */ (
goog.testing.createMethodMock(window.URL, 'revokeObjectURL'));
mockCreateObject(blob).$returns(fakeObjectUrl);
mockRevokeObject(fakeObjectUrl);
mockCreateObject.$replay();
mockRevokeObject.$replay();

var image = goog.dom.safe.createImageFromBlob(blob);

mockCreateObject.$verify();
assertEquals('function', typeof image.onload);
image.onload(null); // Trigger image load.
mockRevokeObject.$verify();
assertEquals(fakeObjectUrl, image.src);
assertTrue(image instanceof HTMLImageElement);
}

function testCreateImageFromBlobBadMimeType() {
// Skip unsupported test if IE9 or lower.
if (goog.userAgent.IE && !goog.userAgent.isVersionOrHigher('10')) {
return;
}
var blob = new Blob(['data'], {type: 'badmimetype'});
assertThrows(function() {
goog.dom.safe.createImageFromBlob(blob);
});
}

/**
* Tests that f raises an AssertionError and runs f while disabling assertion
* errors.

0 comments on commit 6eca8fc

Please sign in to comment.