Use data:// URI rather than blob: URI to avoid XSS

This commit is contained in:
Mark Haines 2016-11-04 15:39:39 +00:00
parent b69e88d4e3
commit ee1768f644
5 changed files with 37 additions and 59 deletions

View file

@ -49,12 +49,10 @@ export default class MAudioBody extends React.Component {
componentDidMount() { componentDidMount() {
var content = this.props.mxEvent.getContent(); var content = this.props.mxEvent.getContent();
if (content.file !== undefined && this.state.decryptedUrl === null) { if (content.file !== undefined && this.state.decryptedUrl === null) {
decryptFile(content.file).then((blob) => { decryptFile(content.file).then((url) => {
if (!this._unmounted) {
this.setState({ this.setState({
decryptedUrl: window.URL.createObjectURL(blob), decryptedUrl: url
}); });
}
}).catch((err) => { }).catch((err) => {
console.warn("Unable to decrypt attachment: ", err) console.warn("Unable to decrypt attachment: ", err)
// Set a placeholder image when we can't decrypt the image. // Set a placeholder image when we can't decrypt the image.
@ -63,13 +61,6 @@ export default class MAudioBody extends React.Component {
} }
} }
componentWillUnmount() {
this._unmounted = true;
if (this.state.decryptedUrl) {
window.URL.revokeObjectURL(this.state.decryptedUrl);
}
}
render() { render() {
var content = this.props.mxEvent.getContent(); var content = this.props.mxEvent.getContent();

View file

@ -22,6 +22,7 @@ var MatrixClientPeg = require('../../../MatrixClientPeg');
var sdk = require('../../../index'); var sdk = require('../../../index');
var DecryptFile = require('../../../utils/DecryptFile'); var DecryptFile = require('../../../utils/DecryptFile');
module.exports = React.createClass({ module.exports = React.createClass({
displayName: 'MFileBody', displayName: 'MFileBody',
@ -66,12 +67,10 @@ module.exports = React.createClass({
var content = this.props.mxEvent.getContent(); var content = this.props.mxEvent.getContent();
var self = this; var self = this;
if (content.file !== undefined && this.state.decryptedUrl === null) { if (content.file !== undefined && this.state.decryptedUrl === null) {
DecryptFile.decryptFile(content.file).then(function(blob) { DecryptFile.decryptFile(content.file).then(function(url) {
if (!self._unmounted) {
self.setState({ self.setState({
decryptedUrl: window.URL.createObjectURL(blob), decryptedUrl: url,
}); });
}
}).catch(function (err) { }).catch(function (err) {
console.warn("Unable to decrypt attachment: ", err) console.warn("Unable to decrypt attachment: ", err)
// Set a placeholder image when we can't decrypt the image. // Set a placeholder image when we can't decrypt the image.
@ -80,13 +79,6 @@ module.exports = React.createClass({
} }
}, },
componentWillUnmount: function() {
this._unmounted = true;
if (this.state.decryptedUrl) {
window.URL.revokeObjectURL(this.state.decryptedUrl);
}
},
render: function() { render: function() {
var content = this.props.mxEvent.getContent(); var content = this.props.mxEvent.getContent();

View file

@ -109,12 +109,10 @@ module.exports = React.createClass({
var content = this.props.mxEvent.getContent(); var content = this.props.mxEvent.getContent();
var self = this; var self = this;
if (content.file !== undefined && this.state.decryptedUrl === null) { if (content.file !== undefined && this.state.decryptedUrl === null) {
DecryptFile.decryptFile(content.file).then(function(blob) { DecryptFile.decryptFile(content.file).then(function(url) {
if (!self._unmounted) {
self.setState({ self.setState({
decryptedUrl: window.URL.createObjectURL(blob), decryptedUrl: url,
}); });
}
}).catch(function (err) { }).catch(function (err) {
console.warn("Unable to decrypt attachment: ", err) console.warn("Unable to decrypt attachment: ", err)
// Set a placeholder image when we can't decrypt the image. // Set a placeholder image when we can't decrypt the image.
@ -125,10 +123,6 @@ module.exports = React.createClass({
componentWillUnmount: function() { componentWillUnmount: function() {
dis.unregister(this.dispatcherRef); dis.unregister(this.dispatcherRef);
this._unmounted = true;
if (this.state.decryptedUrl) {
window.URL.revokeObjectURL(this.state.decryptedUrl);
}
}, },
onAction: function(payload) { onAction: function(payload) {

View file

@ -88,21 +88,13 @@ module.exports = React.createClass({
content.info.thumbnail_file content.info.thumbnail_file
); );
} }
thumbnailPromise.then(function(thumbnailBlob) { thumbnailPromise.then(function(thumbnailUrl) {
DecryptFile.decryptFile( DecryptFile.decryptFile(
content.file content.file
).then(function(contentBlob) { ).then(function(contentUrl) {
if (self._unmounted) {
return;
}
var contentUrl = window.URL.createObjectURL(contentBlob);
var thumbUrl = null;
if (thumbnailBlob) {
thumbUrl = window.URL.createObjectURL(thumbnailBlob);
}
self.setState({ self.setState({
decryptedUrl: contentUrl, decryptedUrl: contentUrl,
decryptedThumbnailUrl: thumbUrl, decryptedThumbnailUrl: thumbnailUrl,
}); });
}); });
}).catch(function (err) { }).catch(function (err) {
@ -113,17 +105,6 @@ module.exports = React.createClass({
} }
}, },
componentWillUnmount: function() {
this._unmounted = true;
if (this.state.decryptedUrl) {
window.URL.revokeObjectURL(this.state.decryptedUrl);
}
if (this.state.decryptedThumbnailUrl) {
window.URL.revokeObjectURL(this.state.decryptedThumbnailUrl);
}
},
render: function() { render: function() {
var content = this.props.mxEvent.getContent(); var content = this.props.mxEvent.getContent();

View file

@ -22,6 +22,26 @@ var encrypt = require("browser-encrypt-attachment");
require("isomorphic-fetch"); require("isomorphic-fetch");
// Grab the client so that we can turn mxc:// URLs into https:// URLS. // Grab the client so that we can turn mxc:// URLs into https:// URLS.
var MatrixClientPeg = require('../MatrixClientPeg'); var MatrixClientPeg = require('../MatrixClientPeg');
var q = require('q');
/**
* Read blob as a data:// URI.
* @return {Promise} A promise that resolves with the data:// URI.
*/
function readBlobAsDataUri(file) {
var deferred = q.defer();
var reader = new FileReader();
reader.onload = function(e) {
deferred.resolve(e.target.result);
};
reader.onerror = function(e) {
deferred.reject(e);
};
reader.readAsDataURL(file);
return deferred.promise;
}
export function decryptFile(file) { export function decryptFile(file) {
@ -37,6 +57,6 @@ export function decryptFile(file) {
}).then(function(dataArray) { }).then(function(dataArray) {
// Turn the array into a Blob and give it the correct MIME-type. // Turn the array into a Blob and give it the correct MIME-type.
var blob = new Blob([dataArray], {type: file.mimetype}); var blob = new Blob([dataArray], {type: file.mimetype});
return blob; return readBlobAsDataUri(blob);
}); });
} }