From 6b9ffe8dd18543479e99584bb36717e049f11bdc Mon Sep 17 00:00:00 2001 From: yflory Date: Tue, 7 Nov 2017 14:51:53 +0100 Subject: [PATCH] Make thumbnails more secure --- www/common/common-thumbnail.js | 31 +++++++++++++++++------------- www/common/cryptpad-common.js | 10 +++++++++- www/common/sframe-app-framework.js | 2 +- www/common/sframe-common-outer.js | 14 ++++++++++++++ www/common/sframe-common.js | 27 ++++++++++++++++++++++---- www/common/sframe-protocol.js | 6 +++++- www/poll/inner.js | 2 +- www/whiteboard/inner.js | 2 +- 8 files changed, 72 insertions(+), 22 deletions(-) diff --git a/www/common/common-thumbnail.js b/www/common/common-thumbnail.js index 5f5a8106a..6ec60d063 100644 --- a/www/common/common-thumbnail.js +++ b/www/common/common-thumbnail.js @@ -4,9 +4,8 @@ define([ '/common/visible.js', '/common/common-hash.js', '/file/file-crypto.js', - '/bower_components/localforage/dist/localforage.min.js', '/bower_components/tweetnacl/nacl-fast.min.js', -], function ($, Util, Visible, Hash, FileCrypto, localForage) { +], function ($, Util, Visible, Hash, FileCrypto) { var Nacl = window.nacl; var Thumb = { dimension: 100, @@ -196,7 +195,7 @@ define([ require(['/bower_components/html2canvas/build/html2canvas.min.js'], todo); }; - Thumb.initPadThumbnails = function (opts) { + Thumb.initPadThumbnails = function (common, opts) { if (!opts.href || !opts.getContent) { throw new Error("href and getContent are needed for thumbnails"); } @@ -206,7 +205,7 @@ define([ if (content === oldThumbnailState) { return; } Thumb.fromDOM(opts, function (err, b64) { oldThumbnailState = content; - Thumb.setPadThumbnail(opts.href, b64); + Thumb.setPadThumbnail(common, opts.href, b64); }); }; var nafa = Util.notAgainForAnother(mkThumbnail, Thumb.UPDATE_INTERVAL); @@ -238,15 +237,19 @@ define([ $span.prepend(img); cb($(img)); }; - Thumb.setPadThumbnail = function (href, b64, cb) { + var getKey = function (href) { + var parsed = Hash.parsePadUrl(href); + return 'thumbnail-' + parsed.type + '-' + parsed.hashData.channel; + }; + Thumb.setPadThumbnail = function (common, href, b64, cb) { cb = cb || function () {}; - var k ='thumbnail-' + href; - localForage.setItem(k, b64, cb); + var k = getKey(href); + common.setThumbnail(k, b64, cb); }; - Thumb.displayThumbnail = function (href, $container, cb) { + Thumb.displayThumbnail = function (common, href, $container, cb) { cb = cb || function () {}; var parsed = Hash.parsePadUrl(href); - var k ='thumbnail-' + href; + var k = getKey(href); var whenNewThumb = function () { var secret = Hash.getSecrets('file', parsed.hash); var hexFileName = Util.base64ToHex(secret.channel); @@ -254,15 +257,17 @@ define([ var cryptKey = secret.keys && secret.keys.fileKeyStr; var key = Nacl.util.decodeBase64(cryptKey); FileCrypto.fetchDecryptedMetadata(src, key, function (e, metadata) { - if (!metadata.thumbnail) { - return void localForage.setItem(k, 'EMPTY'); + var v = metadata.thumbnail; + if (!v) { + v = 'EMPTY'; } - localForage.setItem(k, metadata.thumbnail, function (err) { + Thumb.setPadThumbnail(common, href, v, function (err) { + if (!metadata.thumbnail) { return; } addThumbnail(err, metadata.thumbnail, $container, cb); }); }); }; - localForage.getItem(k, function (err, v) { + common.getThumbnail(k, function (err, v) { if (!v && parsed.type === 'file') { // We can only create thumbnails for files here since we can't easily decrypt pads return void whenNewThumb(); diff --git a/www/common/cryptpad-common.js b/www/common/cryptpad-common.js index 9789a5ce8..9826427a3 100644 --- a/www/common/cryptpad-common.js +++ b/www/common/cryptpad-common.js @@ -21,9 +21,10 @@ define([ '/customize/application_config.js', '/common/media-tag.js', '/bower_components/nthen/index.js', + '/bower_components/localforage/dist/localforage.min.js', ], function ($, Config, Messages, Store, Util, Hash, UI, History, UserList, Title, Metadata, Messaging, CodeMirror, Files, FileCrypto, Realtime, Clipboard, - Pinpad, AppConfig, MediaTag, Nthen) { + Pinpad, AppConfig, MediaTag, Nthen, localForage) { // Configure MediaTags to use our local viewer if (MediaTag && MediaTag.PdfPlugin) { @@ -519,6 +520,13 @@ define([ }); }; + common.setThumbnail = function (key, value, cb) { + localForage.setItem(key, value, cb); + }; + common.getThumbnail = function (key, cb) { + localForage.getItem(key, cb); + }; + /* this returns a reference to your proxy. changing it will change your drive. */ var getFileEntry = common.getFileEntry = function (href, cb) { diff --git a/www/common/sframe-app-framework.js b/www/common/sframe-app-framework.js index d58710e1b..342108678 100644 --- a/www/common/sframe-app-framework.js +++ b/www/common/sframe-app-framework.js @@ -276,7 +276,7 @@ define([ if (!cpNfInner.chainpad) { return; } return cpNfInner.chainpad.getUserDoc(); }; - Thumb.initPadThumbnails(options.thumbnail); + Thumb.initPadThumbnails(common, options.thumbnail); } } diff --git a/www/common/sframe-common-outer.js b/www/common/sframe-common-outer.js index 0f07ac8a3..abab4761b 100644 --- a/www/common/sframe-common-outer.js +++ b/www/common/sframe-common-outer.js @@ -309,6 +309,20 @@ define([ }); }); + sframeChan.on('Q_THUMBNAIL_GET', function (data, cb) { + Cryptpad.getThumbnail(data.key, function (e, data) { + cb({ + error: e, + data: data + }); + }); + }); + sframeChan.on('Q_THUMBNAIL_SET', function (data, cb) { + Cryptpad.setThumbnail(data.key, data.value, function (e) { + cb({error:e}); + }); + }); + sframeChan.on('Q_SESSIONSTORAGE_PUT', function (data, cb) { sessionStorage[data.key] = data.value; cb(); diff --git a/www/common/sframe-common.js b/www/common/sframe-common.js index 2a539e88e..1fd8981fb 100644 --- a/www/common/sframe-common.js +++ b/www/common/sframe-common.js @@ -15,7 +15,8 @@ define([ '/common/cryptpad-common.js', '/common/common-realtime.js', '/common/common-util.js', - '/common/common-thumbnail.js' + '/common/common-thumbnail.js', + '/bower_components/localforage/dist/localforage.min.js' ], function ( $, nThen, @@ -32,9 +33,9 @@ define([ Cryptpad, CommonRealtime, Util, - Thumb + Thumb, + localForage ) { - // Chainpad Netflux Inner var funcs = {}; var ctx = {}; @@ -84,7 +85,7 @@ define([ funcs.updateTags = callWithCommon(UI.updateTags); // Thumb - funcs.displayThumbnail = Thumb.displayThumbnail; + funcs.displayThumbnail = callWithCommon(Thumb.displayThumbnail); // History funcs.getHistory = callWithCommon(History.create); @@ -218,6 +219,22 @@ define([ }, cb); }; + // Thumbnails + funcs.setThumbnail = function (key, value, cb) { + cb = cb || $.noop; + ctx.sframeChan.query('Q_THUMBNAIL_SET', { + key: key, + value: value + }, cb); + }; + funcs.getThumbnail = function (key, cb) { + ctx.sframeChan.query('Q_THUMBNAIL_GET', { + key: key + }, function (err, res) { + cb (err || res.error, res.data); + }); + }; + funcs.sessionStorage = { put: function (key, value, cb) { ctx.sframeChan.query('Q_SESSIONSTORAGE_PUT', { @@ -310,6 +327,8 @@ define([ SFrameChannel.create(window.parent, waitFor(function (sfc) { ctx.sframeChan = sfc; }), true); // CpNfInner.start() should be here.... }).nThen(function () { + localForage.clear(); + ctx.metadataMgr = MetadataMgr.create(ctx.sframeChan); ctx.sframeChan.whenReg('EV_CACHE_PUT', function () { diff --git a/www/common/sframe-protocol.js b/www/common/sframe-protocol.js index 846502120..e41bc129f 100644 --- a/www/common/sframe-protocol.js +++ b/www/common/sframe-protocol.js @@ -171,5 +171,9 @@ define({ // Add or remove the avatar from the profile. // We have to pin/unpin the avatar and store/remove the value from the user object 'Q_PROFILE_AVATAR_ADD': true, - 'Q_PROFILE_AVATAR_REMOVE': true + 'Q_PROFILE_AVATAR_REMOVE': true, + + // Store outside and get thumbnails inside (stored with localForage (indexedDB) outside) + 'Q_THUMBNAIL_SET': true, + 'Q_THUMBNAIL_GET': true, }); diff --git a/www/poll/inner.js b/www/poll/inner.js index 783ed9afc..ad7752a3d 100644 --- a/www/poll/inner.js +++ b/www/poll/inner.js @@ -837,7 +837,7 @@ define([ href: href, getContent: function () { return JSON.stringify(APP.proxy.content); } }; - Thumb.initPadThumbnails(options); + Thumb.initPadThumbnails(common, options); }; var checkDeletedCells = function () { diff --git a/www/whiteboard/inner.js b/www/whiteboard/inner.js index 7550cb98d..e52cb6828 100644 --- a/www/whiteboard/inner.js +++ b/www/whiteboard/inner.js @@ -390,7 +390,7 @@ define([ var D = Thumb.getResizedDimensions($canvas[0], 'pad'); Thumb.fromCanvas($canvas[0], D, function (err, b64) { oldThumbnailState = content; - Thumb.setPadThumbnail(href, b64); + Thumb.setPadThumbnail(common, href, b64); }); }; window.setInterval(mkThumbnail, Thumb.UPDATE_INTERVAL);