diff --git a/customize.dist/src/less2/include/markdown.less b/customize.dist/src/less2/include/markdown.less index af3ac74d8..f88d8ca7c 100644 --- a/customize.dist/src/less2/include/markdown.less +++ b/customize.dist/src/less2/include/markdown.less @@ -64,26 +64,7 @@ } } -.markdown_cryptpad() { - word-wrap: break-word; - - h1, h2, h3, h4, h5, h6 { - font-weight: bold; - padding-bottom: 0.3em; - border-bottom: 1px solid #eee; - } - li { - min-height: 22px; - } - .todo-list-item { - list-style: none; - position: relative; - .fa { - position: absolute; - margin-left: -17px; - margin-top: 4px; - } - } +.mediatag_cryptpad() { media-tag { cursor: pointer; * { @@ -126,6 +107,30 @@ display: inline-block; border: 1px solid #BBB; } +} + +.markdown_cryptpad() { + word-wrap: break-word; + + h1, h2, h3, h4, h5, h6 { + font-weight: bold; + padding-bottom: 0.3em; + border-bottom: 1px solid #eee; + } + li { + min-height: 22px; + } + .todo-list-item { + list-style: none; + position: relative; + .fa { + position: absolute; + margin-left: -17px; + margin-top: 4px; + } + } + + .mediatag_cryptpad(); pre.markmap { border: 1px solid #ddd; diff --git a/customize.dist/src/less2/include/modals-ui-elements.less b/customize.dist/src/less2/include/modals-ui-elements.less index 27eb233da..ff40729a6 100644 --- a/customize.dist/src/less2/include/modals-ui-elements.less +++ b/customize.dist/src/less2/include/modals-ui-elements.less @@ -1,6 +1,7 @@ @import (reference) "./colortheme-all.less"; @import (reference) "./variables.less"; @import (reference) "./browser.less"; +@import (reference) "./markdown.less"; .modals-ui-elements_main() { --LessLoader_require: LessLoader_currentFile(); @@ -214,6 +215,7 @@ flex: 1; min-width: 0; overflow: auto; + .mediatag_cryptpad(); media-tag { & > * { max-width: 100%; diff --git a/www/common/common-thumbnail.js b/www/common/common-thumbnail.js index 8c78d9d6d..012c2c9b4 100644 --- a/www/common/common-thumbnail.js +++ b/www/common/common-thumbnail.js @@ -3,9 +3,9 @@ define([ '/common/common-util.js', '/common/visible.js', '/common/common-hash.js', - '/file/file-crypto.js', + '/common/media-tag.js', '/bower_components/tweetnacl/nacl-fast.min.js', -], function ($, Util, Visible, Hash, FileCrypto) { +], function ($, Util, Visible, Hash, MediaTag) { var Nacl = window.nacl; var Thumb = { dimension: 100, @@ -314,7 +314,7 @@ define([ var hexFileName = secret.channel; var src = fileHost + Hash.getBlobPathFromHex(hexFileName); var key = secret.keys && secret.keys.cryptKey; - FileCrypto.fetchDecryptedMetadata(src, key, function (e, metadata) { + MediaTag.fetchDecryptedMetadata(src, key, function (e, metadata) { if (e) { if (e === 'XHR_ERROR') { return; } return console.error(e); diff --git a/www/common/media-tag.js b/www/common/media-tag.js index 446dfdf08..a00377ff4 100644 --- a/www/common/media-tag.js +++ b/www/common/media-tag.js @@ -125,7 +125,6 @@ var factory = function () { }; var makeProgressBar = function (cfg, mediaObject) { - // XXX CSP: we'll need to add style in cryptpad's less if (mediaObject.bar) { return; } mediaObject.bar = true; var style = (function(){/* @@ -151,10 +150,10 @@ var factory = function () { } .mediatag-progress-text { height: 25px; + width: 50px; margin-left: 5px; line-height: 25px; vertical-align: top; - width: auto; display: inline-block; color: #3F4141; font-weight: bold; @@ -618,6 +617,7 @@ var factory = function () { var handlers = cfg.handlers || { 'progress': [], 'complete': [], + 'metadata': [], 'error': [] }; @@ -700,8 +700,7 @@ var factory = function () { if (errDecryption) { return void reject(errDecryption); } - // XXX emit 'metadata' u8Decrypted.metadata - // Cache and display the decrypted blob + emit('metadata', u8Decrypted.metadata); resolve(u8Decrypted); }, function (progress) { emit('progress', { @@ -736,21 +735,18 @@ var factory = function () { var maxSize = typeof(config.maxDownloadSize) === "number" ? config.maxDownloadSize : (5 * 1024 * 1024); - getFileSize(src, function (err, size) { - if (err) { - return void error(err); - } - // If the size is smaller than the autodownload limit, load the blob. - // If the blob is already loaded or being loaded, don't show the button. - if (!size || size < maxSize || getCache()) { - makeProgressBar(cfg, mediaObject); - return void dl(); - } - var sizeMb = Math.round(10 * size / 1024 / 1024) / 10; - fetchDecryptedMetadata(src, strKey, function (err, md) { - if (err) { return void error(err); } - cfg.metadata = md; - // XXX emit 'metadata' + fetchDecryptedMetadata(src, strKey, function (err, md) { + if (err) { return void error(err); } + cfg.metadata = md; + emit('metadata', md); + getFileSize(src, function (err, size) { + // If the size is smaller than the autodownload limit, load the blob. + // If the blob is already loaded or being loaded, don't show the button. + if (!size || size < maxSize || getCache()) { + makeProgressBar(cfg, mediaObject); + return void dl(); + } + var sizeMb = Math.round(10 * size / 1024 / 1024) / 10; makeDownloadButton(cfg, mediaObject, sizeMb, dl); }); }); @@ -765,6 +761,8 @@ var factory = function () { config[key] = value; }; + init.fetchDecryptedMetadata = fetchDecryptedMetadata; + return init; }; diff --git a/www/file/app-file.less b/www/file/app-file.less index d6e8ad69c..be7e067f1 100644 --- a/www/file/app-file.less +++ b/www/file/app-file.less @@ -1,5 +1,6 @@ @import (reference) '../../customize/src/less2/include/tokenfield.less'; @import (reference) '../../customize/src/less2/include/framework.less'; +@import (reference) '../../customize/src/less2/include/markdown.less'; &.cp-app-file { @@ -47,6 +48,7 @@ z-index: -1; } + .mediatag_cryptpad(); media-tag { img { max-width: 100%; @@ -198,6 +200,9 @@ max-height: 100%; max-width: 100%; } + &:empty { + display: none !important; + } } } diff --git a/www/file/file-crypto.js b/www/file/file-crypto.js index 12453bb48..6a0c08816 100644 --- a/www/file/file-crypto.js +++ b/www/file/file-crypto.js @@ -48,69 +48,6 @@ define([ return new Blob(chunks); }; - var concatBuffer = function (a, b) { // TODO make this not so ugly - return new Uint8Array(slice(a).concat(slice(b))); - }; - - var fetchMetadata = function (src, cb) { - var done = false; - var CB = function (err, res) { - if (done) { return; } - done = true; - cb(err, res); - }; - - var xhr = new XMLHttpRequest(); - xhr.open("GET", src, true); - xhr.setRequestHeader('Range', 'bytes=0-1'); - xhr.responseType = 'arraybuffer'; - - xhr.onerror= function () { return CB('XHR_ERROR'); }; - xhr.onload = function () { - if (/^4/.test('' + this.status)) { return CB('XHR_ERROR'); } - var res = new Uint8Array(xhr.response); - var size = decodePrefix(res); - var xhr2 = new XMLHttpRequest(); - - xhr2.open("GET", src, true); - xhr2.setRequestHeader('Range', 'bytes=2-' + (size + 2)); - xhr2.responseType = 'arraybuffer'; - xhr2.onload = function () { - if (/^4/.test('' + this.status)) { return CB('XHR_ERROR'); } - var res2 = new Uint8Array(xhr2.response); - var all = concatBuffer(res, res2); - CB(void 0, all); - }; - xhr2.send(null); - }; - xhr.send(null); - }; - - var decryptMetadata = function (u8, key) { - var prefix = u8.subarray(0, 2); - var metadataLength = decodePrefix(prefix); - - var metaBox = new Uint8Array(u8.subarray(2, 2 + metadataLength)); - var metaChunk = Nacl.secretbox.open(metaBox, createNonce(), key); - - try { - return JSON.parse(Nacl.util.encodeUTF8(metaChunk)); - } - catch (e) { return null; } - }; - - var fetchDecryptedMetadata = function (src, key, cb) { - if (typeof(src) !== 'string') { - return window.setTimeout(function () { - cb('NO_SOURCE'); - }); - } - fetchMetadata(src, function (e, buffer) { - if (e) { return cb(e); } - cb(void 0, decryptMetadata(buffer, key)); - }); - }; - var decrypt = function (u8, key, done, progress) { var MAX = u8.length; var _progress = function (offset) { @@ -268,8 +205,5 @@ define([ encrypt: encrypt, joinChunks: joinChunks, computeEncryptedSize: computeEncryptedSize, - decryptMetadata: decryptMetadata, - fetchMetadata: fetchMetadata, - fetchDecryptedMetadata: fetchDecryptedMetadata, }; }); diff --git a/www/file/inner.html b/www/file/inner.html index a3e5070e4..45ba831fe 100644 --- a/www/file/inner.html +++ b/www/file/inner.html @@ -16,7 +16,6 @@ - diff --git a/www/file/inner.js b/www/file/inner.js index 6cc129de5..59291c964 100644 --- a/www/file/inner.js +++ b/www/file/inner.js @@ -43,7 +43,6 @@ define([ var andThen = function (common) { var $appContainer = $('#cp-app-file-content'); var $form = $('#cp-app-file-upload-form'); - var $dlform = $('#cp-app-file-download-form'); var $dlview = $('#cp-app-file-download-view'); var $label = $form.find('label'); var $bar = $('.cp-toolbar-container'); @@ -86,36 +85,44 @@ define([ if (!uploadMode) { (function () { - Messages.download = "Download"; // XXX - Messages.decrypt = "Decrypt"; // XXX - - var progress = h('div.cp-app-file-progress'); - var progressTxt = h('span.cp-app-file-progress-txt'); - var $progress = $(progress); - var $progressTxt = $(progressTxt); - var downloadEl = h('span.cp-app-file-progress-dl', Messages.download); - var decryptEl = h('span.cp-app-file-progress-dc', Messages.decrypt); - var progressContainer = h('div.cp-app-file-progress-container', [ - downloadEl, - decryptEl, - progress - ]); - var hexFileName = secret.channel; var src = fileHost + Hash.getBlobPathFromHex(hexFileName); var key = secret.keys && secret.keys.cryptKey; var cryptKey = Nacl.util.encodeBase64(key); - FileCrypto.fetchDecryptedMetadata(src, key, function (e, metadata) { - if (e) { - if (e === 'XHR_ERROR') { - return void UI.errorLoadingScreen(Messages.download_resourceNotAvailable, false, function () { - common.gotoURL('/file/'); - }); - } - return void console.error(e); + var $mt = $dlview.find('media-tag'); + $mt.attr('src', src); + $mt.attr('data-crypto-key', 'cryptpad:'+cryptKey); + $mt.css('transform', 'scale(2)'); + + var rightsideDisplayed = false; + var metadataReceived = false; + UI.removeLoadingScreen(); + $dlview.show(); + + MediaTag($mt[0]).on('complete', function (decrypted) { + $mt.css('transform', ''); + if (!rightsideDisplayed) { + toolbar.$drawer + .append(common.createButton('export', true, {}, function () { + saveAs(decrypted.content, decrypted.metadata.name); + })); + rightsideDisplayed = true; } + // make pdfs big + var toolbarHeight = $('#cp-toolbar').height(); + $('media-tag iframe').css({ + 'height': 'calc(100vh - ' + toolbarHeight + 'px)', + 'width': '100vw', + 'position': 'absolute', + 'bottom': 0, + 'left': 0, + 'border': 0 + }); + }).on('metadata', function (metadata) { + if (metadataReceived) { return; } + metadataReceived = true; // Add pad attributes when the file is saved in the drive Title.onTitleChange(function () { var owners = metadata.owners; @@ -150,106 +157,11 @@ define([ toolbar.$drawer.append(common.createButton('hashtag', true)); } toolbar.$file.show(); - - var displayFile = function (ev, sizeMb, CB) { - var called_back; - var cb = function (e) { - if (called_back) { return; } - called_back = true; - if (CB) { CB(e); } - }; - - var $mt = $dlview.find('media-tag'); - $mt.attr('src', src); - $mt.attr('data-crypto-key', 'cryptpad:'+cryptKey); - - var rightsideDisplayed = false; - - MediaTag($mt[0], { - force: true // Download starts automatically - }).on('complete', function (decrypted) { - $dlview.show(); - $dlform.hide(); - var $dlButton = $dlview.find('media-tag button'); - if (ev) { $dlButton.click(); } - - if (!rightsideDisplayed) { - toolbar.$drawer - .append(common.createButton('export', true, {}, function () { - saveAs(decrypted.content, decrypted.metadata.name); - })); - rightsideDisplayed = true; - } - - // make pdfs big - var toolbarHeight = $('#cp-toolbar').height(); - var $another_iframe = $('media-tag iframe').css({ - 'height': 'calc(100vh - ' + toolbarHeight + 'px)', - 'width': '100vw', - 'position': 'absolute', - 'bottom': 0, - 'left': 0, - 'border': 0 - }); - - if ($another_iframe.length) { - $another_iframe.load(function () { - cb(); - }); - } else { - cb(); - } - }).on('progress', function (data) { - var p = data.progress +'%'; - $progress.width(p); - $progressTxt.text(Math.floor(data.progress) + '%'); - }).on('error', function (err) { - console.error(err); - }); - }; - - // XXX Update "download_button" key to use "download" first and "decrypt" second - var todoBigFile = function (sizeMb) { - $dlform.show(); - UI.removeLoadingScreen(); - var button = h('button.btn.btn-primary', { - title: Messages.download_button - }, Messages.download_button); - $dlform.append([ - h('h2', Util.fixHTML(metadata.name)), - h('div.cp-button-container', [ - button, - progressTxt - ]), - ]); - - // don't display the size if you don't know it. - if (typeof(sizeMb) === 'number') { - $dlform.find('h2').append(' - ' + - Messages._getKey('formattedMB', [sizeMb])); - } - var decrypting = false; - var onClick = function (ev) { - if (decrypting) { return; } - decrypting = true; - $(button).prop('disabled', 'disabled'); - $dlform.append(progressContainer); - displayFile(ev, sizeMb, function (err) { - $appContainer.css('background-color', - common.getAppConfig().appBackgroundColor); - if (err) { UI.alert(err); } - }); - }; - if (typeof(sizeMb) === 'number' && sizeMb < 5) { return void onClick(); } - $(button).click(onClick); - }; - common.getFileSize(hexFileName, function (e, data) { - if (e) { - return void UI.errorLoadingScreen(e); - } - var size = Util.bytesToMegabytes(data); - return void todoBigFile(size); - }); + }).on('error', function (err) { + $appContainer.css('background-color', + common.getAppConfig().appBackgroundColor); + UI.warn(Messages.error); + console.error(err); }); })(); return; diff --git a/www/pad/inner.js b/www/pad/inner.js index f9b5dffb9..a22c0d81d 100644 --- a/www/pad/inner.js +++ b/www/pad/inner.js @@ -478,7 +478,7 @@ define([ var list_values = slice(el.children) .map(function (el) { return el.outerHTML; }) .join(''); - mediaMap[el.getAttribute('src')] = list_values; + mediaTagMap[el.getAttribute('src')] = list_values; if (mediaObject.complete) { observer.disconnect(); } } });