diff --git a/src/ContentMessages.js b/src/ContentMessages.js index d20266de50..8665c40ae0 100644 --- a/src/ContentMessages.js +++ b/src/ContentMessages.js @@ -81,6 +81,24 @@ function infoForVideoFile(videoFile) { return deferred.promise; } +/** + * Read the file as an ArrayBuffer. + * @return {Promise} A promise that resolves with an ArrayBuffer when the file + * is read. + */ +function readFileAsArrayBuffer(file) { + const deferred = q.defer(); + const reader = new FileReader(); + reader.onload = function(e) { + deferred.resolve(e.target.result); + }; + reader.onerror = function(e) { + deferred.reject(e); + }; + reader.readAsArrayBuffer(file); + return deferred.promise; +} + class ContentMessages { constructor() { diff --git a/src/components/views/messages/MAudioBody.js b/src/components/views/messages/MAudioBody.js index 34dcb9ba7a..ff753621c7 100644 --- a/src/components/views/messages/MAudioBody.js +++ b/src/components/views/messages/MAudioBody.js @@ -38,7 +38,7 @@ export default class MAudioBody extends React.Component { } _getContentUrl() { - var content = this.props.mxEvent.getContent(); + const content = this.props.mxEvent.getContent(); if (content.file !== undefined) { return this.state.decryptedUrl; } else { @@ -49,11 +49,11 @@ export default class MAudioBody extends React.Component { componentDidMount() { var content = this.props.mxEvent.getContent(); if (content.file !== undefined && this.state.decryptedUrl === null) { - decryptFile(content.file).then((url) => { + decryptFile(content.file).done((url) => { this.setState({ decryptedUrl: url }); - }).catch((err) => { + }, (err) => { console.warn("Unable to decrypt attachment: ", err) // Set a placeholder image when we can't decrypt the image. this.refs.image.src = "img/warning.svg"; @@ -62,7 +62,7 @@ export default class MAudioBody extends React.Component { } render() { - var content = this.props.mxEvent.getContent(); + const content = this.props.mxEvent.getContent(); if (content.file !== undefined && this.state.decryptedUrl === null) { // Need to decrypt the attachment @@ -76,7 +76,7 @@ export default class MAudioBody extends React.Component { ); } - var contentUrl = this._getContentUrl(); + const contentUrl = this._getContentUrl(); return ( diff --git a/src/components/views/messages/MFileBody.js b/src/components/views/messages/MFileBody.js index 1dd3414917..a1512738fd 100644 --- a/src/components/views/messages/MFileBody.js +++ b/src/components/views/messages/MFileBody.js @@ -55,7 +55,7 @@ module.exports = React.createClass({ }, _getContentUrl: function() { - var content = this.props.mxEvent.getContent(); + const content = this.props.mxEvent.getContent(); if (content.file !== undefined) { return this.state.decryptedUrl; } else { @@ -64,25 +64,24 @@ module.exports = React.createClass({ }, componentDidMount: function() { - var content = this.props.mxEvent.getContent(); - var self = this; + const content = this.props.mxEvent.getContent(); if (content.file !== undefined && this.state.decryptedUrl === null) { - DecryptFile.decryptFile(content.file).then(function(url) { - self.setState({ + DecryptFile.decryptFile(content.file).done((url) => { + this.setState({ decryptedUrl: url, }); - }).catch(function (err) { + }, (err) => { console.warn("Unable to decrypt attachment: ", err) // Set a placeholder image when we can't decrypt the image. - self.refs.image.src = "img/warning.svg"; + this.refs.image.src = "img/warning.svg"; }); } }, render: function() { - var content = this.props.mxEvent.getContent(); + const content = this.props.mxEvent.getContent(); - var text = this.presentableTextForFile(content); + const text = this.presentableTextForFile(content); var TintableSvg = sdk.getComponent("elements.TintableSvg"); if (content.file !== undefined && this.state.decryptedUrl === null) { @@ -98,9 +97,9 @@ module.exports = React.createClass({ ); } - var contentUrl = this._getContentUrl(); + const contentUrl = this._getContentUrl(); - var fileName = content.body && content.body.length > 0 ? content.body : "Attachment"; + const fileName = content.body && content.body.length > 0 ? content.body : "Attachment"; var downloadAttr = undefined; if (this.state.decryptedUrl) { diff --git a/src/components/views/messages/MImageBody.js b/src/components/views/messages/MImageBody.js index a75d27d57d..63928e9518 100644 --- a/src/components/views/messages/MImageBody.js +++ b/src/components/views/messages/MImageBody.js @@ -16,17 +16,14 @@ limitations under the License. 'use strict'; -var React = require('react'); -var filesize = require('filesize'); - +import React from 'react'; import MFileBody from './MFileBody'; - -var MatrixClientPeg = require('../../../MatrixClientPeg'); -var ImageUtils = require('../../../ImageUtils'); -var Modal = require('../../../Modal'); -var sdk = require('../../../index'); -var dis = require("../../../dispatcher"); -var DecryptFile = require('../../../utils/DecryptFile'); +import MatrixClientPeg from '../../../MatrixClientPeg'; +import ImageUtils from '../../../ImageUtils'; +import Modal from '../../../Modal'; +import sdk from '../../../index'; +import dis from '../../../dispatcher'; +import DecryptFile from '../../../utils/DecryptFile'; module.exports = React.createClass({ displayName: 'MImageBody', @@ -86,7 +83,7 @@ module.exports = React.createClass({ }, _getContentUrl: function() { - var content = this.props.mxEvent.getContent(); + const content = this.props.mxEvent.getContent(); if (content.file !== undefined) { return this.state.decryptedUrl; } else { @@ -95,7 +92,7 @@ module.exports = React.createClass({ }, _getThumbUrl: function() { - var content = this.props.mxEvent.getContent(); + const content = this.props.mxEvent.getContent(); if (content.file !== undefined) { // TODO: Decrypt and use the thumbnail file if one is present. return this.state.decryptedUrl; @@ -107,17 +104,16 @@ module.exports = React.createClass({ componentDidMount: function() { this.dispatcherRef = dis.register(this.onAction); this.fixupHeight(); - var content = this.props.mxEvent.getContent(); - var self = this; + const content = this.props.mxEvent.getContent(); if (content.file !== undefined && this.state.decryptedUrl === null) { - DecryptFile.decryptFile(content.file).then(function(url) { - self.setState({ + DecryptFile.decryptFile(content.file).done((url) => { + this.setState({ decryptedUrl: url, }); - }).catch(function (err) { + }, (err) => { console.warn("Unable to decrypt attachment: ", err) // Set a placeholder image when we can't decrypt the image. - self.refs.image.src = "img/warning.svg"; + this.refs.image.src = "img/warning.svg"; }); } }, diff --git a/src/components/views/messages/MVideoBody.js b/src/components/views/messages/MVideoBody.js index d1797339a4..4e60e17e40 100644 --- a/src/components/views/messages/MVideoBody.js +++ b/src/components/views/messages/MVideoBody.js @@ -16,15 +16,12 @@ limitations under the License. 'use strict'; -var React = require('react'); -var filesize = require('filesize'); - +import React from require('react'); import MFileBody from './MFileBody'; - -var MatrixClientPeg = require('../../../MatrixClientPeg'); -var Modal = require('../../../Modal'); -var sdk = require('../../../index'); -var DecryptFile = require("../../../utils/DecryptFile") +import MatrixClientPeg from '../../../MatrixClientPeg'; +import Model from '../../../Modal'; +import sdk from '../../../index'; +import DecryptFile from '../../../utils/DecryptFile'; module.exports = React.createClass({ displayName: 'MVideoBody', @@ -59,7 +56,7 @@ module.exports = React.createClass({ }, _getContentUrl: function() { - var content = this.props.mxEvent.getContent(); + const content = this.props.mxEvent.getContent(); if (content.file !== undefined) { return this.state.decryptedUrl; } else { @@ -68,7 +65,7 @@ module.exports = React.createClass({ }, _getThumbUrl: function() { - var content = this.props.mxEvent.getContent(); + const content = this.props.mxEvent.getContent(); if (content.file !== undefined) { return this.state.decryptedThumbnailUrl; } else if (content.info.thumbnail_url) { @@ -79,9 +76,7 @@ module.exports = React.createClass({ }, componentDidMount: function() { - var content = this.props.mxEvent.getContent(); - var self = this; - + const content = this.props.mxEvent.getContent(); if (content.file !== undefined && this.state.decryptedUrl === null) { var thumbnailPromise = Promise.resolve(null); if (content.info.thumbnail_file) { @@ -89,25 +84,25 @@ module.exports = React.createClass({ content.info.thumbnail_file ); } - thumbnailPromise.then(function(thumbnailUrl) { + thumbnailPromise.done((thumbnailUrl) => { DecryptFile.decryptFile( content.file ).then(function(contentUrl) { - self.setState({ + this.setState({ decryptedUrl: contentUrl, decryptedThumbnailUrl: thumbnailUrl, }); }); - }).catch(function (err) { + }, (err) => { console.warn("Unable to decrypt attachment: ", err) // Set a placeholder image when we can't decrypt the image. - self.refs.image.src = "img/warning.svg"; + this.refs.image.src = "img/warning.svg"; }); } }, render: function() { - var content = this.props.mxEvent.getContent(); + const content = this.props.mxEvent.getContent(); if (content.file !== undefined && this.state.decryptedUrl === null) { // Need to decrypt the attachment @@ -121,15 +116,15 @@ module.exports = React.createClass({ ); } - var contentUrl = this._getContentUrl(); - var thumbUrl = this._getThumbUrl(); + const contentUrl = this._getContentUrl(); + const thumbUrl = this._getThumbUrl(); var height = null; var width = null; var poster = null; var preload = "metadata"; if (content.info) { - var scale = this.thumbScale(content.info.w, content.info.h, 480, 360); + const scale = this.thumbScale(content.info.w, content.info.h, 480, 360); if (scale) { width = Math.floor(content.info.w * scale); height = Math.floor(content.info.h * scale); diff --git a/src/utils/DecryptFile.js b/src/utils/DecryptFile.js index 06a098c5fd..ca7cf33584 100644 --- a/src/utils/DecryptFile.js +++ b/src/utils/DecryptFile.js @@ -14,22 +14,19 @@ See the License for the specific language governing permissions and limitations under the License. */ -'use struct'; - // Pull in the encryption lib so that we can decrypt attachments. -var encrypt = require("browser-encrypt-attachment"); +import encrypt from 'browser-encrypt-attachment'; // Pull in a fetch polyfill so we can download encrypted attachments. -require("isomorphic-fetch"); +import 'isomorphic-fetch'; // Grab the client so that we can turn mxc:// URLs into https:// URLS. -var MatrixClientPeg = require('../MatrixClientPeg'); -var q = require('q'); +import MatrixClientPeg from '../MatrixClientPeg'; +import q from '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(); @@ -44,13 +41,21 @@ function readBlobAsDataUri(file) { } +/** + * Decrypt a file attached to a matrix event. + * @param file {Object} The json taken from the matrix event. + * This passed to [link]{@link https://github.com/matrix-org/browser-encrypt-attachments} + * as the encryption info object, so will also have the those keys in addition to + * the keys below. + * @param file.url {string} An mxc:// URL for the encrypted file. + * @param file.mimetype {string} The MIME-type of the plaintext file. + */ export function decryptFile(file) { - var url = MatrixClientPeg.get().mxcUrlToHttp(file.url); - var self = this; + const url = MatrixClientPeg.get().mxcUrlToHttp(file.url); // Download the encrypted file as an array buffer. - return fetch(url).then(function (response) { + return fetch(url).then(function(response) { return response.arrayBuffer(); - }).then(function (responseData) { + }).then(function(responseData) { // Decrypt the array buffer using the information taken from // the event content. return encrypt.decryptAttachment(responseData, file);