diff --git a/customize.dist/src/less2/include/toolbar.less b/customize.dist/src/less2/include/toolbar.less index 0df5823a0..1d1ca0c47 100644 --- a/customize.dist/src/less2/include/toolbar.less +++ b/customize.dist/src/less2/include/toolbar.less @@ -97,6 +97,12 @@ .ckeditor_fix(); + .cp-burn-after-reading { + text-align: center; + font-size: @colortheme_app-font-size !important; + margin: 0 !important; + } + .cp-markdown-toolbar { height: @toolbar_line-height; background-color: @toolbar-bg-color-l20; diff --git a/www/code/inner.js b/www/code/inner.js index e2ed086de..e933bd4bd 100644 --- a/www/code/inner.js +++ b/www/code/inner.js @@ -98,6 +98,7 @@ define([ }; var mkHelpMenu = function (framework) { var $codeMirrorContainer = $('#cp-app-code-container'); + $codeMirrorContainer.prepend(framework._.sfCommon.getBurnAfterReadingWarning()); var helpMenu = framework._.sfCommon.createHelpMenu(['text', 'code']); $codeMirrorContainer.prepend(helpMenu.menu); diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index d9f0af36c..1964ed570 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -3978,6 +3978,7 @@ define([ UIElements.onServerError = function (common, err, toolbar, cb) { if (["EDELETED", "EEXPIRED"].indexOf(err.type) === -1) { return; } + var priv = common.getMetadataMgr().getPrivateData(); var msg = err.type; if (err.type === 'EEXPIRED') { msg = Messages.expiredError; @@ -3985,6 +3986,7 @@ define([ msg += Messages.errorCopy; } } else if (err.type === 'EDELETED') { + if (priv.burnAfterReading) { return void cb(); } msg = Messages.deletedError; if (err.loaded) { msg += Messages.errorCopy; @@ -4034,6 +4036,26 @@ define([ $password.find('.cp-password-input').focus(); }; + UIElements.displayBurnAfterReadingPage = function (common, cb) { + var info = h('p.cp-password-info', 'XXX Burn after reading'); // XXX + var button = h('button', 'Proceed'); // XXX + + $(button).on('click', function () { + cb(); + }); + + var block = h('div#cp-loading-burn-after-reading', [ + info, + button + ]); + UI.errorLoadingScreen(block); + }; + UIElements.getBurnAfterReadingWarning = function (common) { + var priv = common.getMetadataMgr().getPrivateData(); + if (!priv.burnAfterReading) { return; } + return h('div.alert.alert-danger.cp-burn-after-reading', 'Pewpewpew'); // XXX + }; + var crowdfundingState = false; UIElements.displayCrowdfunding = function (common) { if (crowdfundingState) { return; } @@ -4091,6 +4113,9 @@ define([ if (data && data.stored) { return; } // We won't display the popup for dropped files var priv = common.getMetadataMgr().getPrivateData(); + // This pad will be deleted automatically, it shouldn't be stored + if (priv.burnAfterReading) { return; } + var typeMsg = priv.pathname.indexOf('/file/') !== -1 ? Messages.autostore_file : priv.pathname.indexOf('/drive/') !== -1 ? Messages.autostore_sf : Messages.autostore_pad; diff --git a/www/common/cryptpad-common.js b/www/common/cryptpad-common.js index 57815b3ef..a0057c59a 100644 --- a/www/common/cryptpad-common.js +++ b/www/common/cryptpad-common.js @@ -847,6 +847,10 @@ define([ postMessage('GET_PAD_METADATA', data, cb); }; + common.burnPad = function (data) { + postMessage('BURN_PAD', data); + }; + common.changePadPassword = function (Crypt, Crypto, data, cb) { var href = data.href; var newPassword = data.password; diff --git a/www/common/onlyoffice/inner.js b/www/common/onlyoffice/inner.js index 0958b024d..a40ccccae 100644 --- a/www/common/onlyoffice/inner.js +++ b/www/common/onlyoffice/inner.js @@ -926,6 +926,7 @@ define([ $rightside.append($forget); var helpMenu = common.createHelpMenu(['beta', 'oo']); + $('#cp-app-oo-editor').prepend(common.getBurnAfterReadingWarning()); $('#cp-app-oo-editor').prepend(helpMenu.menu); toolbar.$drawer.append(helpMenu.button); diff --git a/www/common/outer/async-store.js b/www/common/outer/async-store.js index 870a539e7..1d1f26ba3 100644 --- a/www/common/outer/async-store.js +++ b/www/common/outer/async-store.js @@ -9,6 +9,7 @@ define([ '/common/common-feedback.js', '/common/common-realtime.js', '/common/common-messaging.js', + '/common/pinpad.js', '/common/outer/sharedfolder.js', '/common/outer/cursor.js', '/common/outer/onlyoffice.js', @@ -26,7 +27,7 @@ define([ '/bower_components/nthen/index.js', '/bower_components/saferphore/index.js', ], function (Sortify, UserObject, ProxyManager, Migrate, Hash, Util, Constants, Feedback, - Realtime, Messaging, + Realtime, Messaging, Pinpad, SF, Cursor, OnlyOffice, Mailbox, Profile, Team, Messenger, NetConfig, AppConfig, Crypto, ChainPad, CpNetflux, Listmap, nThen, Saferphore) { @@ -409,19 +410,17 @@ define([ var initRpc = function (clientId, data, cb) { if (!store.loggedIn) { return cb(); } if (store.rpc) { return void cb(account); } - require(['/common/pinpad.js'], function (Pinpad) { - Pinpad.create(store.network, store.proxy, function (e, call) { - if (e) { return void cb({error: e}); } + Pinpad.create(store.network, store.proxy, function (e, call) { + if (e) { return void cb({error: e}); } - store.rpc = call; + store.rpc = call; - Store.getPinLimit(null, null, function (obj) { - if (obj.error) { console.error(obj.error); } - account.limit = obj.limit; - account.plan = obj.plan; - account.note = obj.note; - cb(obj); - }); + Store.getPinLimit(null, null, function (obj) { + if (obj.error) { console.error(obj.error); } + account.limit = obj.limit; + account.plan = obj.plan; + account.note = obj.note; + cb(obj); }); }); }; @@ -1653,6 +1652,28 @@ define([ cb(); }; + // Delete a pad received with a burn after reading URL + Store.burnPad = function (clientId, data, cb) { + var channel = data.channel; + var ownerKey = Crypto.b64AddSlashes(data.ownerKey || ''); + if (!channel || !ownerKey) { return void console.error("Can't delete BAR pad"); } + try { + var signKey = Hash.decodeBase64(ownerKey); + var pair = Crypto.Nacl.sign.keyPair.fromSecretKey(signKey); + Pinpad.create(store.network, { + edPublic: Hash.encodeBase64(pair.publicKey), + edPrivate: Hash.encodeBase64(pair.secretKey) + }, function (e, rpc) { + if (e) { return void console.error(e); } + rpc.removeOwnedChannel(channel, function (err) { + if (err) { console.error(err); } + }); + }); + } catch (e) { + console.error(e); + } + }; + // Fetch the latest version of the metadata on the server and return it. // If the pad is stored in our drive, update the local values of "owners" and "expire" Store.getPadMetadata = function (clientId, data, cb) { diff --git a/www/common/outer/store-rpc.js b/www/common/outer/store-rpc.js index 49250582f..41963402b 100644 --- a/www/common/outer/store-rpc.js +++ b/www/common/outer/store-rpc.js @@ -80,6 +80,7 @@ define([ IS_NEW_CHANNEL: Store.isNewChannel, REQUEST_PAD_ACCESS: Store.requestPadAccess, GIVE_PAD_ACCESS: Store.givePadAccess, + BURN_PAD: Store.burnPad, GET_PAD_METADATA: Store.getPadMetadata, SET_PAD_METADATA: Store.setPadMetadata, CHANGE_PAD_PASSWORD_PIN: Store.changePadPasswordPin, diff --git a/www/common/sframe-common-outer.js b/www/common/sframe-common-outer.js index 9308f05cb..c19e9e344 100644 --- a/www/common/sframe-common-outer.js +++ b/www/common/sframe-common-outer.js @@ -323,6 +323,7 @@ define([ } Utils.crypto = Utils.Crypto.createEncryptor(Utils.secret.keys); var parsed = Utils.Hash.parsePadUrl(window.location.href); + var burnAfterReading = parsed && parsed.hashData && parsed.hashData.ownerKey; if (!parsed.type) { throw new Error(); } var defaultTitle = Utils.UserObject.getDefaultName(parsed); var edPublic, curvePublic, notifications, isTemplate; @@ -376,6 +377,7 @@ define([ fromFileData: Cryptpad.fromFileData ? { title: Cryptpad.fromFileData.title } : undefined, + burnAfterReading: burnAfterReading, storeInTeam: Cryptpad.initialTeam || (Cryptpad.initialPath ? -1 : undefined) }; if (window.CryptPad_newSharedFolder) { @@ -1235,6 +1237,14 @@ define([ window.location.hash = hash; }; + if (burnAfterReading) { + Cryptpad.padRpc.onReadyEvent.reg(function () { + Cryptpad.burnPad({ + channel: secret.channel, + ownerKey: burnAfterReading + }); + }); + } var cpNfCfg = { sframeChan: sframeChan, channel: secret.channel, @@ -1358,12 +1368,17 @@ define([ }); }); + sframeChan.on('EV_BURN_AFTER_READING', function () { + startRealtime(); + }); + sframeChan.ready(); Utils.Feedback.reportAppUsage(); if (!realtime && !Test.testing) { return; } if (isNewFile && cfg.useCreationScreen && !Test.testing) { return; } + if (burnAfterReading) { return; } //if (isNewFile && Utils.LocalStore.isLoggedIn() // && AppConfig.displayCreationScreen && cfg.useCreationScreen) { return; } diff --git a/www/common/sframe-common.js b/www/common/sframe-common.js index f8bbb205b..9e51d46de 100644 --- a/www/common/sframe-common.js +++ b/www/common/sframe-common.js @@ -96,6 +96,7 @@ define([ funcs.createMarkdownToolbar = callWithCommon(UIElements.createMarkdownToolbar); funcs.createHelpMenu = callWithCommon(UIElements.createHelpMenu); funcs.getPadCreationScreen = callWithCommon(UIElements.getPadCreationScreen); + funcs.getBurnAfterReadingWarning = callWithCommon(UIElements.getBurnAfterReadingWarning); funcs.createNewPadModal = callWithCommon(UIElements.createNewPadModal); funcs.onServerError = callWithCommon(UIElements.onServerError); funcs.importMediaTagMenu = callWithCommon(UIElements.importMediaTagMenu); @@ -300,6 +301,13 @@ define([ } // If we display the pad creation screen, it will handle deleted pads directly funcs.getPadCreationScreen(c, config, waitFor()); + return; + } + if (priv.burnAfterReading) { + UIElements.displayBurnAfterReadingPage(funcs, waitFor(function () { + UI.addLoadingScreen(); + ctx.sframeChan.event('EV_BURN_AFTER_READING'); + })); } }; funcs.createPad = function (cfg, cb) { diff --git a/www/kanban/inner.js b/www/kanban/inner.js index 5a9e10f47..621d56cae 100644 --- a/www/kanban/inner.js +++ b/www/kanban/inner.js @@ -350,6 +350,8 @@ define([ var mkHelpMenu = function (framework) { var $toolbarContainer = $('#cp-app-kanban-container'); + $toolbarContainer.prepend(framework._.sfCommon.getBurnAfterReadingWarning()); + var helpMenu = framework._.sfCommon.createHelpMenu(['kanban']); $toolbarContainer.prepend(helpMenu.menu); diff --git a/www/pad/inner.js b/www/pad/inner.js index 5db93837c..78f027182 100644 --- a/www/pad/inner.js +++ b/www/pad/inner.js @@ -190,6 +190,7 @@ define([ var mkHelpMenu = function (framework) { var $toolbarContainer = $('.cke_toolbox_main'); + $toolbarContainer.before(framework._.sfCommon.getBurnAfterReadingWarning()); var helpMenu = framework._.sfCommon.createHelpMenu(['text', 'pad']); $toolbarContainer.before(helpMenu.menu); diff --git a/www/poll/inner.js b/www/poll/inner.js index ba8fd7d65..7420f5c09 100644 --- a/www/poll/inner.js +++ b/www/poll/inner.js @@ -1187,6 +1187,7 @@ define([ $drawer.append($export); var helpMenu = common.createHelpMenu(['poll']); + $('#cp-app-poll-form').prepend(common.getBurnAfterReadingWarning()); $('#cp-app-poll-form').prepend(helpMenu.menu); $drawer.append(helpMenu.button); diff --git a/www/slide/inner.js b/www/slide/inner.js index 6d97bf8e5..5736828d5 100644 --- a/www/slide/inner.js +++ b/www/slide/inner.js @@ -410,6 +410,7 @@ define([ var mkHelpMenu = function (framework) { var $codeMirrorContainer = $('#cp-app-slide-editor-container'); + $codeMirrorContainer.prepend(framework._.sfCommon.getBurnAfterReadingWarning()); var helpMenu = framework._.sfCommon.createHelpMenu(['text', 'slide']); $codeMirrorContainer.prepend(helpMenu.menu); diff --git a/www/whiteboard/inner.js b/www/whiteboard/inner.js index a90dd4187..77057f505 100644 --- a/www/whiteboard/inner.js +++ b/www/whiteboard/inner.js @@ -270,6 +270,7 @@ define([ var mkHelpMenu = function (framework) { var $appContainer = $('#cp-app-whiteboard-container'); + $appContainer.prepend(framework._.sfCommon.getBurnAfterReadingWarning()); var helpMenu = framework._.sfCommon.createHelpMenu(['whiteboard']); $appContainer.prepend(helpMenu.menu); framework._.toolbar.$drawer.append(helpMenu.button);