From 073025b4e4643addbc3271edef9ca4b80a221311 Mon Sep 17 00:00:00 2001 From: yflory Date: Thu, 8 Oct 2020 17:53:39 +0200 Subject: [PATCH 01/21] Import a template into a spreadsheet --- www/common/common-ui-elements.js | 1 + www/common/cryptpad-common.js | 1 + www/common/onlyoffice/inner.js | 133 ++++++++++++++++++++++++++---- www/common/sframe-common-outer.js | 8 ++ www/secureiframe/inner.js | 1 + 5 files changed, 129 insertions(+), 15 deletions(-) diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index 35ab93cda..1a78f3bc2 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -639,6 +639,7 @@ define([ button .click(common.prepareFeedback(type)) .click(function () { + if (callback) { return void callback(); } UIElements.openTemplatePicker(common, true); }); break; diff --git a/www/common/cryptpad-common.js b/www/common/cryptpad-common.js index 85de0b006..ddf63389c 100644 --- a/www/common/cryptpad-common.js +++ b/www/common/cryptpad-common.js @@ -638,6 +638,7 @@ define([ if (!val) { return void cb('ENOENT'); } + if (data.oo) { return void cb(val); } // OnlyOffice template: are handled in inner try { // Try to fix the title before importing the template var parsed = JSON.parse(val); diff --git a/www/common/onlyoffice/inner.js b/www/common/onlyoffice/inner.js index ea0e51bfc..92931411b 100644 --- a/www/common/onlyoffice/inner.js +++ b/www/common/onlyoffice/inner.js @@ -415,7 +415,7 @@ define([ clearTimeout(pendingChanges[key]); delete pendingChanges[key]; }); - if (APP.stopHistory) { APP.history = false; } + if (APP.stopHistory || APP.template) { APP.history = false; } startOO(blob, type, true); }; @@ -425,14 +425,15 @@ define([ var file = getFileType(); blob.name = (metadataMgr.getMetadataLazy().title || file.doc) + '.' + file.type; var data = { - hash: APP.history ? ooChannel.historyLastHash : ooChannel.lastHash, - index: APP.history ? ooChannel.currentIndex : ooChannel.cpIndex + hash: (APP.history || APP.template) ? ooChannel.historyLastHash : ooChannel.lastHash, + index: (APP.history || APP.template) ? ooChannel.currentIndex : ooChannel.cpIndex }; fixSheets(); ooChannel.ready = false; ooChannel.queue = []; data.callback = function () { + if (APP.template) { APP.template = false; } resetData(blob, file); }; @@ -1295,6 +1296,13 @@ define([ } } + if (APP.template) { + getEditor().setViewModeDisconnect(); + UI.removeLoadingScreen(); + makeCheckpoint(true); + return; + } + if (APP.history) { try { getEditor().asc_setRestriction(true); @@ -1828,6 +1836,108 @@ define([ pinImages(); }; + var loadCp = function (cp, keepQueue) { + loadLastDocument(cp, function () { + var file = getFileType(); + var type = common.getMetadataMgr().getPrivateData().ooType; + var blob = loadInitDocument(type, true); + if (!keepQueue) { ooChannel.queue = []; } + resetData(blob, file); + }, function (blob, file) { + if (!keepQueue) { ooChannel.queue = []; } + resetData(blob, file); + }); + }; + + var loadTemplate = function (href, pw, parsed) { + APP.history = true; + APP.template = true; + getEditor().setViewModeDisconnect(); + var content = parsed.content; + + // Get checkpoint + var hashes = content.hashes || {}; + var idx = sortCpIndex(hashes); + var lastIndex = idx[idx.length - 1]; + var lastCp = hashes[lastIndex]; + + // Current cp or initial hash (invalid hash ==> initial hash) + var toHash = lastCp.hash || 'NONE'; + // Last hash + var fromHash = 'NONE'; + + sframeChan.query('Q_GET_HISTORY_RANGE', { + href: href, + password: pw, + channel: content.channel, + lastKnownHash: fromHash, + toHash: toHash, + }, function (err, data) { + if (err) { return void console.error(err); } + if (!Array.isArray(data.messages)) { return void console.error('Not an array!'); } + + // The first "cp" in history is the empty doc. It doesn't include the first patch + // of the history + var initialCp = !lastCp.hash; + + var messages = (data.messages || []).slice(initialCp ? 0 : 1); + + ooChannel.queue = messages.map(function (obj) { + return { + hash: obj.serverHash, + msg: JSON.parse(obj.msg) + }; + }); + ooChannel.historyLastHash = ooChannel.lastHash; + ooChannel.currentIndex = ooChannel.cpIndex; + console.error(ooChannel.historyLastHash); + loadCp(lastCp, true); + }); + }; + + var openTemplatePicker = function () { + var metadataMgr = common.getMetadataMgr(); + var type = metadataMgr.getPrivateData().app; + var sframeChan = common.getSframeChannel(); + var pickerCfgInit = { + types: [type], + where: ['template'], + hidden: true + }; + var pickerCfg = { + types: [type], + where: ['template'], + }; + var onConfirm = function () { + common.openFilePicker(pickerCfg, function (data) { + if (data.type !== type) { return; } + UI.addLoadingScreen({hideTips: true}); + sframeChan.query('Q_OO_TEMPLATE_USE', { + href: data.href, + }, function (err, val) { + var parsed; + try { + parsed = JSON.parse(val); + } catch (e) { + console.error(e, val); + UI.removeLoadingScreen(); + return void UI.warn(Messages.error); + } + console.error(data); + loadTemplate(data.href, data.password, parsed); + }); + }); + }; + sframeChan.query("Q_TEMPLATE_EXIST", type, function (err, data) { + if (data) { + common.openFilePicker(pickerCfgInit); + onConfirm(); + } else { + UI.alert(Messages.template_empty); + } + }); + }; + config.onInit = function (info) { var privateData = metadataMgr.getPrivateData(); @@ -1849,6 +1959,7 @@ define([ Title.setToolbar(toolbar); if (window.CP_DEV_MODE) { + var $save = common.createButton('save', true, {}, function () { makeCheckpoint(true); }); @@ -1865,18 +1976,6 @@ define([ APP.stopHistory = true; makeCheckpoint(true); }; - var loadCp = function (cp, keepQueue) { - loadLastDocument(cp, function () { - var file = getFileType(); - var type = common.getMetadataMgr().getPrivateData().ooType; - var blob = loadInitDocument(type, true); - if (!keepQueue) { ooChannel.queue = []; } - resetData(blob, file); - }, function (blob, file) { - if (!keepQueue) { ooChannel.queue = []; } - resetData(blob, file); - }); - }; var onPatch = function (patch) { // Patch on the current cp ooChannel.send(JSON.parse(patch.msg)); @@ -1970,6 +2069,10 @@ define([ load: loadSnapshot }); toolbar.$drawer.append($snapshot); + + // Import template + var $template = common.createButton('importtemplate', true, {}, openTemplatePicker); + $template.appendTo(toolbar.$drawer); })(); } diff --git a/www/common/sframe-common-outer.js b/www/common/sframe-common-outer.js index bba393afb..b0feaee4f 100644 --- a/www/common/sframe-common-outer.js +++ b/www/common/sframe-common-outer.js @@ -1102,6 +1102,10 @@ define([ nSecret = Utils.Hash.getSecrets('drive', hash, password); } } + if (data.href) { + var _parsed = Utils.Hash.parsePadUrl(data.href); + nSecret = Utils.Hash.getSecrets(_parsed.type, _parsed.hash, data.password); + } var channel = nSecret.channel; var validate = nSecret.keys.validateKey; var crypto = Crypto.createEncryptor(nSecret.keys); @@ -1282,6 +1286,10 @@ define([ sframeChan.on('Q_TEMPLATE_USE', function (data, cb) { Cryptpad.useTemplate(data, Cryptget, cb); }); + sframeChan.on('Q_OO_TEMPLATE_USE', function (data, cb) { + data.oo = true; + Cryptpad.useTemplate(data, Cryptget, cb); + }); sframeChan.on('Q_TEMPLATE_EXIST', function (type, cb) { Cryptpad.listTemplates(type, function (err, templates) { cb(templates.length > 0); diff --git a/www/secureiframe/inner.js b/www/secureiframe/inner.js index 344a4fb39..c20d53a80 100644 --- a/www/secureiframe/inner.js +++ b/www/secureiframe/inner.js @@ -124,6 +124,7 @@ define([ } sframeChan.event("EV_SECURE_ACTION", { type: parsed.type, + password: data.password, href: data.url, name: data.name }); From a16b43b25c86e3139e4377e0865ace86a0721bde Mon Sep 17 00:00:00 2001 From: yflory Date: Fri, 9 Oct 2020 15:24:32 +0200 Subject: [PATCH 02/21] Add templates for OnlyOffice in the PCS --- www/common/common-ui-elements.js | 2 +- www/common/onlyoffice/inner.js | 22 +++++++++++++++++----- www/common/sframe-common-outer.js | 24 ++++++++++++++++++++++++ 3 files changed, 42 insertions(+), 6 deletions(-) diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index 1a78f3bc2..882153c99 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -2094,7 +2094,7 @@ define([ var sframeChan = common.getSframeChannel(); var metadataMgr = common.getMetadataMgr(); var privateData = metadataMgr.getPrivateData(); - var type = metadataMgr.getMetadataLazy().type; + var type = metadataMgr.getMetadataLazy().type || privateData.app; var fromFileData = privateData.fromFileData; var $body = $('body'); diff --git a/www/common/onlyoffice/inner.js b/www/common/onlyoffice/inner.js index 92931411b..14b03935b 100644 --- a/www/common/onlyoffice/inner.js +++ b/www/common/onlyoffice/inner.js @@ -113,6 +113,7 @@ define([ }; var getEditor = function () { + if (!window.frames || !window.frames[0]) { return; } return window.frames[0].editor || window.frames[0].editorCell; }; @@ -1852,14 +1853,15 @@ define([ var loadTemplate = function (href, pw, parsed) { APP.history = true; APP.template = true; - getEditor().setViewModeDisconnect(); + var editor = getEditor(); + if (editor) { editor.setViewModeDisconnect(); } var content = parsed.content; // Get checkpoint var hashes = content.hashes || {}; var idx = sortCpIndex(hashes); var lastIndex = idx[idx.length - 1]; - var lastCp = hashes[lastIndex]; + var lastCp = hashes[lastIndex] || {}; // Current cp or initial hash (invalid hash ==> initial hash) var toHash = lastCp.hash || 'NONE'; @@ -2231,11 +2233,18 @@ define([ openRtChannel(function () { setMyId(); oldHashes = JSON.parse(JSON.stringify(content.hashes)); - loadDocument(newDoc, useNewDefault); initializing = false; + common.openPadChat(APP.onLocal); + + if (APP.startWithTemplate) { + var template = APP.startWithTemplate; + loadTemplate(template.href, template.password, template.content); + return; + } + + loadDocument(newDoc, useNewDefault); setEditable(!readOnly); UI.removeLoadingScreen(); - common.openPadChat(APP.onLocal); }); }; @@ -2359,8 +2368,11 @@ define([ })); SFCommon.create(waitFor(function (c) { APP.common = common = c; })); }).nThen(function (waitFor) { + common.getSframeChannel().on('EV_OO_TEMPLATE', function (data) { + APP.startWithTemplate = data; + }); common.handleNewFile(waitFor, { - noTemplates: true + //noTemplates: true }); }).nThen(function (/*waitFor*/) { andThen(common); diff --git a/www/common/sframe-common-outer.js b/www/common/sframe-common-outer.js index b0feaee4f..bc2175f62 100644 --- a/www/common/sframe-common-outer.js +++ b/www/common/sframe-common-outer.js @@ -1646,6 +1646,7 @@ define([ rtConfig.metadata.validateKey = (secret.keys && secret.keys.validateKey) || undefined; Utils.rtConfig = rtConfig; + var templatePw; nThen(function(waitFor) { if (data.templateId) { if (data.templateId === -1) { @@ -1654,11 +1655,34 @@ define([ } Cryptpad.getPadData(data.templateId, waitFor(function (err, d) { data.template = d.href; + templatePw = d.password; })); } }).nThen(function () { var cryptputCfg = $.extend(true, {}, rtConfig, {password: password}); if (data.template) { + // Start OO with a template... + // Cryptget and give href, password and content to inner + if (parsed.type === "sheet") { + var then = function () { + startRealtime(rtConfig); + cb(); + }; + var _parsed = Utils.Hash.parsePadUrl(data.template); + Cryptget.get(_parsed.hash, function (err, val) { + if (err || !val) { return void then(); } + try { + var parsed = JSON.parse(val); + sframeChan.event('EV_OO_TEMPLATE', { + href: data.template, + password: templatePw, + content: parsed + }); + } catch (e) { console.error(e); } + then(); + }, {password: templatePw}); + return; + } // Pass rtConfig to useTemplate because Cryptput will create the file and // we need to have the owners and expiration time in the first line on the // server From 7588dcd631f6561073f0011e14128769da17ed0f Mon Sep 17 00:00:00 2001 From: yflory Date: Fri, 9 Oct 2020 15:51:57 +0200 Subject: [PATCH 03/21] Remove dev log --- www/common/onlyoffice/inner.js | 1 - 1 file changed, 1 deletion(-) diff --git a/www/common/onlyoffice/inner.js b/www/common/onlyoffice/inner.js index 14b03935b..eca46476b 100644 --- a/www/common/onlyoffice/inner.js +++ b/www/common/onlyoffice/inner.js @@ -1892,7 +1892,6 @@ define([ }); ooChannel.historyLastHash = ooChannel.lastHash; ooChannel.currentIndex = ooChannel.cpIndex; - console.error(ooChannel.historyLastHash); loadCp(lastCp, true); }); }; From 4c206ec10181e14cfd9c5c912e2d6d41ab712ec5 Mon Sep 17 00:00:00 2001 From: ansuz Date: Fri, 23 Oct 2020 10:15:41 +0530 Subject: [PATCH 04/21] optimize Util.throttle for extremely high call frequencies --- www/common/common-util.js | 37 +++++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/www/common/common-util.js b/www/common/common-util.js index 0e86ecc8c..eba7ad5f9 100644 --- a/www/common/common-util.js +++ b/www/common/common-util.js @@ -306,11 +306,44 @@ }; Util.throttle = function (f, ms) { + var last = 0; var to; + var args; + + var defer = function (delay) { + console.log("setTimeout(stuff, %s)", delay); + // no timeout: run function `f` in `ms` milliseconds + // unless `g` is called again in the meantime + to = setTimeout(function () { + // wipe the current timeout handler + to = undefined; + + // take the current time + var now = +new Date(); + // compute time passed since `last` + var diff = now - last; + if (diff < ms) { + // don't run `f` if `g` was called since this timeout was set + // instead calculate how much further in the future your next + // timeout should be scheduled + return void defer(ms - diff); + } + + // else run `f` with the most recently supplied arguments + f.apply(null, args); + }, ms); + }; + var g = function () { - clearTimeout(to); - to = setTimeout(Util.bake(f, Util.slice(arguments)), ms); + // every time you call this function store the time + last = +new Date(); + // remember what arguments were passed + args = Util.slice(arguments); + // if there is a pending timeout then do nothing + if (to) { return; } + defer(ms); }; + g.clear = function () { clearTimeout(to); to = undefined; From d1e263f0e8de42f87f48891e5e44ca0061920b46 Mon Sep 17 00:00:00 2001 From: ansuz Date: Fri, 23 Oct 2020 10:20:24 +0530 Subject: [PATCH 05/21] remove annoying console.log --- www/common/common-util.js | 1 - 1 file changed, 1 deletion(-) diff --git a/www/common/common-util.js b/www/common/common-util.js index eba7ad5f9..e781bc2eb 100644 --- a/www/common/common-util.js +++ b/www/common/common-util.js @@ -311,7 +311,6 @@ var args; var defer = function (delay) { - console.log("setTimeout(stuff, %s)", delay); // no timeout: run function `f` in `ms` milliseconds // unless `g` is called again in the meantime to = setTimeout(function () { From 08d889b8a470a59ede4371a341a777f7240b721f Mon Sep 17 00:00:00 2001 From: ansuz Date: Fri, 23 Oct 2020 10:35:29 +0530 Subject: [PATCH 06/21] fix an incorrect reference and add a small script to help profile timer accuracy --- scripts/tests/throttle-test.js | 34 ++++++++++++++++++++++++++++++++++ www/common/common-util.js | 2 +- 2 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 scripts/tests/throttle-test.js diff --git a/scripts/tests/throttle-test.js b/scripts/tests/throttle-test.js new file mode 100644 index 000000000..e84fc4a8a --- /dev/null +++ b/scripts/tests/throttle-test.js @@ -0,0 +1,34 @@ +var Util = require("../../lib/common-util"); + +(function (throttle) { + var last = 0; + var last_call = 0; + var f = Util.throttle(function (boop) { + var now = +new Date(); + if (last) { + console.log("last execution was %sms ago", now - last); + } else { + console.log("this is the first execution"); + } + last = now; + + //console.log('time of execution:', now); + console.log(boop); + }, 1000); + + [150, 250, 580, 850, 1500, 2200, 3990, 5000].forEach(function (delay) { + setTimeout(function () { + var now = +new Date(); + + if (last_call) { + console.log("last call was %sms ago", now - last_call); + } + + last_call = now; + //console.log("time of call for delay(%s):", delay, now); + f(delay); + }, delay); + }); +}(Util.throttle2)); + + diff --git a/www/common/common-util.js b/www/common/common-util.js index e781bc2eb..41797e7c8 100644 --- a/www/common/common-util.js +++ b/www/common/common-util.js @@ -330,7 +330,7 @@ // else run `f` with the most recently supplied arguments f.apply(null, args); - }, ms); + }, delay); }; var g = function () { From d2dce35f9b9ac2cf808ceb3c50400653063e785a Mon Sep 17 00:00:00 2001 From: ansuz Date: Fri, 23 Oct 2020 12:35:44 +0530 Subject: [PATCH 07/21] update changelog and version string for 3.23.2 (XerusDaamsi reloaded) --- CHANGELOG.md | 33 +++++++++++++++++++++++++++++++++ customize.dist/pages.js | 2 +- package-lock.json | 2 +- package.json | 2 +- 4 files changed, 36 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 30661d523..9f649883d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,36 @@ +# XerusDaamsi reloaded (3.23.2) + +A number of instance administrators reported issues following our 3.23.1 release. We suspect the issues were caused by applying the recommended update steps out of order which would result in the incorrect HTTP header values getting cached for the most recent version of a file. Since the most recently updated headers modified some security settings, this caused a catastrophic error on clients receiving the incorrect headers which caused them to fail to load under certain circumstances. + +Regardless of the reasons behind this, we want CryptPad to be resilient against misconfiguration. This minor release includes a number of measures to override the unruly caching mechanisms employed internally by two of our most stubborn dependencies (CKEditor and OnlyOffice). Deploying 3.23.2 should force these editors to load the most recent versions of these dependencies according to the same policies as the rest of CryptPad and instruct clients to ignore any incorrect server responses they might have cached over the last few updates. + +This release also includes a number of bug fixes which had been tested in the meantime. + +Other bug fixes + +* We removed a hardcoded translation pertaining to the recently introduced "snapshot" functionality. +* Inspection of our server logs revealed a number of rare race conditions and type errors that have since been addressed. These included: + * multiple invocations of a callback when iterating over the list of all encrypted blobs + * a type error when recovering from the crash of one of the database worker processes + * premature closure of filesystem read-streams due to a timeout when the server was under heavy load +* A thorough review of our teams functionality revealed the possibility of some similarly rare issues that have since been corrected: + * it was possible to click the buttons on the "team invitation response dialog" multiple times before the first action completed. In some cases this could result in attempting to join a single team multiple times. + * it was also possible to activate trigger several actions that would modify your access rights for a team when the team had not fully synchronized with the server. Some of the time this was recoverable, but it could occasionally result in your team membership getting stuck in a bad state. + +We've implemented some measures to correct any team data that might have become corrupted due to the issues described above. Access rights from duplicated teams should be merged back into one set of cryptographic keys wherever possible. In cases where this isn't possible your role in the team will be automatically downgraded to the rank conferred by the keys you still have. For instance, somebody listed as an administrator who only has the keys required to view the team will downgrade themself to be a viewer. Subsequent promotions back to your previous team role should restore your possession of the required keys. + +To update to 3.23.2 from 3.23.0 or 3.23.1: + +Perform the same upgrade steps listed for 3.23.0 including the most recent configuration changes listed in `cryptpad/docs/example.nginx.conf... + +1. Modify your server's NGINX config file (but don't apply its changes until step 6) +2. Stop CryptPad's nodejs server +3. Get the latest platform code with git +4. Install client-side dependencies with `bower update` +5. Install server-side dependencies with `npm install` +6. Reload NGINX with `service nginx reload` to apply its config changes +7. Restart the CryptPad API server + # XerusDaamsi's revenge (3.23.1) We discovered a number of minor bugs after deploying 3.23.0. This minor release addresses them. diff --git a/customize.dist/pages.js b/customize.dist/pages.js index 2bd67b906..1db764bcc 100644 --- a/customize.dist/pages.js +++ b/customize.dist/pages.js @@ -62,7 +62,7 @@ define([ var imprintUrl = AppConfig.imprint && (typeof(AppConfig.imprint) === "boolean" ? '/imprint.html' : AppConfig.imprint); - Pages.versionString = "CryptPad v3.23.1 (XerusDaamsi's revenge)"; + Pages.versionString = "CryptPad v3.23.2 (XerusDaamsi reloaded)"; // used for the about menu Pages.imprintLink = AppConfig.imprint ? footLink(imprintUrl, 'imprint') : undefined; diff --git a/package-lock.json b/package-lock.json index 40d00411f..a9ee6e5e7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "cryptpad", - "version": "3.23.1", + "version": "3.23.2", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 6f4fa275e..a849b2c2d 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "cryptpad", "description": "realtime collaborative visual editor with zero knowlege server", - "version": "3.23.1", + "version": "3.23.2", "license": "AGPL-3.0+", "repository": { "type": "git", From d25d9c4f83570d3da60ad85f7ef80cc74373d195 Mon Sep 17 00:00:00 2001 From: yflory Date: Mon, 26 Oct 2020 14:57:54 +0100 Subject: [PATCH 08/21] Fix UI issues when printing code --- customize.dist/src/less2/include/app-print.less | 9 +++++---- customize.dist/src/print-landscape.css | 5 +++++ customize.dist/src/print.css | 4 ++++ www/code/app-code.less | 1 - www/code/inner.js | 1 + www/pad/inner.html | 2 +- www/pad/inner.js | 7 +++++++ www/slide/inner.js | 1 + 8 files changed, 24 insertions(+), 6 deletions(-) create mode 100644 customize.dist/src/print-landscape.css create mode 100644 customize.dist/src/print.css diff --git a/customize.dist/src/less2/include/app-print.less b/customize.dist/src/less2/include/app-print.less index e4c344b20..7f42f100b 100644 --- a/customize.dist/src/less2/include/app-print.less +++ b/customize.dist/src/less2/include/app-print.less @@ -9,10 +9,6 @@ max-height: none; overflow: visible; display: block; - @page { - margin: 0; - size: landscape; - } // Slide app body.cp-app-slide { display: block; @@ -48,11 +44,15 @@ // Code app body.cp-app-code { display: block; + height: auto; * { visibility: hidden; height: auto; max-height: none; } + .cp-toolbar-userlist-drawer { + display: none; + } #cme_toolbox { display: none; } @@ -64,6 +64,7 @@ #cp-app-code-preview { display: block; #cp-app-code-print { + font-size: 20px; display: block; overflow: visible !important; width: 100%; diff --git a/customize.dist/src/print-landscape.css b/customize.dist/src/print-landscape.css new file mode 100644 index 000000000..26a9d495e --- /dev/null +++ b/customize.dist/src/print-landscape.css @@ -0,0 +1,5 @@ +@page { + margin: 0; + size: A4 landscape; +} + diff --git a/customize.dist/src/print.css b/customize.dist/src/print.css new file mode 100644 index 000000000..1baf803d4 --- /dev/null +++ b/customize.dist/src/print.css @@ -0,0 +1,4 @@ +@page { + margin: 3cm; + size: A4 portrait; +} diff --git a/www/code/app-code.less b/www/code/app-code.less index 0ca86fd8b..6557d39f6 100644 --- a/www/code/app-code.less +++ b/www/code/app-code.less @@ -136,7 +136,6 @@ #cp-app-code-print { position: relative; display: none; - margin: 50px; .markdown_preformatted-code; .markdown_gfm-table(black); } diff --git a/www/code/inner.js b/www/code/inner.js index 1956ab3f4..68b58bce4 100644 --- a/www/code/inner.js +++ b/www/code/inner.js @@ -42,6 +42,7 @@ define([ 'cm/addon/fold/comment-fold', 'cm/addon/display/placeholder', + 'css!/customize/src/print.css', 'less!/code/app-code.less' ], function ( diff --git a/www/pad/inner.html b/www/pad/inner.html index b7ccd4d00..e4dbcdf95 100644 --- a/www/pad/inner.html +++ b/www/pad/inner.html @@ -1,5 +1,5 @@ - + diff --git a/www/pad/inner.js b/www/pad/inner.js index 19c2063d8..eeabbb337 100644 --- a/www/pad/inner.js +++ b/www/pad/inner.js @@ -47,6 +47,7 @@ define([ '/bower_components/diff-dom/diffDOM.js', + 'css!/customize/src/print.css', 'css!/bower_components/bootstrap/dist/css/bootstrap.min.css', 'css!/bower_components/components-font-awesome/css/font-awesome.min.css', 'less!/pad/app-pad.less' @@ -500,6 +501,12 @@ define([ var mkPrintButton = function (framework, editor) { var $printButton = framework._.sfCommon.createButton('print', true); $printButton.click(function () { + /* + // NOTE: alternative print system in case we keep having more issues on Firefox + var $iframe = $('html').find('iframe'); + var iframe = $iframe[0].contentWindow; + iframe.print(); + */ editor.execCommand('print'); framework.feedback('PRINT_PAD'); }); diff --git a/www/slide/inner.js b/www/slide/inner.js index 3af7185c5..de30eb9fc 100644 --- a/www/slide/inner.js +++ b/www/slide/inner.js @@ -15,6 +15,7 @@ define([ 'css!/bower_components/bootstrap/dist/css/bootstrap.min.css', 'css!/bower_components/components-font-awesome/css/font-awesome.min.css', + 'css!/customize/src/print-landscape.css', 'less!/slide/app-slide.less', 'css!cm/lib/codemirror.css', From 4df7fb93f813e37c5e11dfa3440a3896fb8b9510 Mon Sep 17 00:00:00 2001 From: yflory Date: Thu, 29 Oct 2020 14:06:16 +0100 Subject: [PATCH 09/21] Stop using sessionStorage when creating/opening pads --- www/common/common-hash.js | 29 +++++++++++ www/common/cryptpad-common.js | 35 ++++++------- www/common/drive-ui.js | 87 +++++++++++++------------------ www/common/notifications.js | 24 ++++----- www/common/sframe-common-outer.js | 81 +++++++++++++++------------- 5 files changed, 137 insertions(+), 119 deletions(-) diff --git a/www/common/common-hash.js b/www/common/common-hash.js index 0b584d4c3..ff8764da4 100644 --- a/www/common/common-hash.js +++ b/www/common/common-hash.js @@ -169,6 +169,17 @@ Version 1 /code/#/1/edit/3Ujt4F2Sjnjbis6CoYWpoQ/usn4+9CqVja8Q7RZOGTfRgqI */ + var getNewPadOpts = function (hashArr) { + var k; + // Check if we have a ownerKey for this pad + hashArr.some(function (data) { + if (/^newpad=/.test(data)) { + k = data.slice(7); + return true; + } + }); + return k || ''; + }; var getVersionHash = function (hashArr) { var k; // Check if we have a ownerKey for this pad @@ -202,6 +213,7 @@ Version 1 parsed.present = options.indexOf('present') !== -1; parsed.embed = options.indexOf('embed') !== -1; parsed.versionHash = getVersionHash(options); + parsed.newPadOpts = getNewPadOpts(options); parsed.ownerKey = getOwnerKey(options); }; @@ -217,6 +229,13 @@ Version 1 password: parsed.password }; }; + + if (/^\/newpad=/.test(hash)) { + return { + newPadOpts: hash.slice(8, -1) + }; + } + if (hash.slice(0,1) !== '/' && hash.length >= 56) { // Version 0 // Old hash parsed.channel = hash.slice(0, 32); @@ -237,6 +256,9 @@ Version 1 if (versionHash) { hash += 'hash=' + Crypto.b64RemoveSlashes(versionHash) + '/'; } + if (opts.newPadOpts) { + hash += 'newpad=' + opts.newPadOpts + '/'; + } return hash; }; @@ -372,6 +394,10 @@ Version 1 var url = '/'; if (!ret.type) { return url; } url += ret.type + '/'; + // New pad with options: append the options to the hash + if (!ret.hashData && options.newPadOpts) { + return url + '#/newpad=' + options.newPadOpts + '/'; + } if (!ret.hashData) { return url; } if (ret.hashData.type !== 'pad') { return url + '#' + ret.hash; } if (ret.hashData.version === 0) { return url + '#' + ret.hash; } @@ -575,6 +601,9 @@ Version 1 // Valid hash? if (parsed.hash) { if (!parsed.hashData) { return; } + // New pad: only newPadOpts allowed + if (Object.keys(parsed.hashData).length === 1 && + parsed.hashData.newPadOpts) { return true; } // Version should be a number if (typeof(parsed.hashData.version) === "undefined") { return; } // pads and files should have a base64 (or hex) key diff --git a/www/common/cryptpad-common.js b/www/common/cryptpad-common.js index a9b2923a9..3e65168a8 100644 --- a/www/common/cryptpad-common.js +++ b/www/common/cryptpad-common.js @@ -148,6 +148,21 @@ define([ send(); }; + common.setTabHref = function (href) { + var ohc = window.onhashchange; + window.onhashchange = function () {}; + window.location.href = href; + window.onhashchange = ohc; + ohc({reset: true}); + }; + common.setTabHash = function (hash) { + var ohc = window.onhashchange; + window.onhashchange = function () {}; + window.location.hash = hash; + window.onhashchange = ohc; + ohc({reset: true}); + }; + // RESTRICTED // Settings only common.resetDrive = function (cb) { @@ -2089,26 +2104,6 @@ define([ language: common.getLanguage(), driveEvents: true //rdyCfg.driveEvents // Boolean }; - // if a pad is created from a file - if (sessionStorage[Constants.newPadFileData]) { - common.fromFileData = JSON.parse(sessionStorage[Constants.newPadFileData]); - var _parsed1 = Hash.parsePadUrl(common.fromFileData.href); - var _parsed2 = Hash.parsePadUrl(window.location.href); - if (_parsed1.hashData.type === 'pad') { - if (_parsed1.type !== _parsed2.type) { delete common.fromFileData; } - } - delete sessionStorage[Constants.newPadFileData]; - } - - if (sessionStorage[Constants.newPadPathKey]) { - common.initialPath = sessionStorage[Constants.newPadPathKey]; - delete sessionStorage[Constants.newPadPathKey]; - } - - if (sessionStorage[Constants.newPadTeamKey]) { - common.initialTeam = sessionStorage[Constants.newPadTeamKey]; - delete sessionStorage[Constants.newPadTeamKey]; - } var channelIsReady = waitFor(); diff --git a/www/common/drive-ui.js b/www/common/drive-ui.js index 5d6a71b9d..08a3f1279 100644 --- a/www/common/drive-ui.js +++ b/www/common/drive-ui.js @@ -1125,6 +1125,18 @@ define([ var hiddenHref = Hash.hashToHref(hash, parsed.type); window.open(APP.origin + hiddenHref); }; + var openIn = function (type, path, team, fData) { + var obj = JSON.stringify({ + p: path, + t: team, + d: fData + }); + var str = encodeURIComponent(obj); + var parsed = Hash.parsePadUrl(Hash.hashToHref('', type)); + var opts = parsed.getOptions(); + opts.newPadOpts = str; + common.openURL(parsed.getUrl(opts)); + }; var refresh = APP.refresh = function () { APP.displayDirectory(currentPath); @@ -2667,12 +2679,7 @@ define([ .click(function () { var type = $(this).attr('data-type') || 'pad'; var path = manager.isPathIn(currentPath, [TRASH]) ? '' : currentPath; - nThen(function (waitFor) { - common.sessionStorage.put(Constants.newPadPathKey, path, waitFor()); - common.sessionStorage.put(Constants.newPadTeamKey, APP.team, waitFor()); - }).nThen(function () { - common.openURL('/' + type + '/'); - }); + openIn(type, path, APP.team); }); }; var createNewButton = function (isInRoot, $container) { @@ -4227,31 +4234,19 @@ define([ else if ($this.hasClass('cp-app-drive-context-makeacopy')) { if (paths.length !== 1) { return; } el = manager.find(paths[0].path); - var _metadata = manager.getFileData(el); - var _simpleData = { - title: _metadata.filename || _metadata.title, - href: _metadata.href || _metadata.roHref, - password: _metadata.password, - channel: _metadata.channel, - }; - nThen(function (waitFor) { + (function () { var path = currentPath; if (path[0] !== ROOT) { path = [ROOT]; } - common.sessionStorage.put(Constants.newPadFileData, JSON.stringify(_simpleData), waitFor()); - common.sessionStorage.put(Constants.newPadPathKey, path, waitFor()); - common.sessionStorage.put(Constants.newPadTeamKey, APP.team, waitFor()); - }).nThen(function () { + var _metadata = manager.getFileData(el); + var _simpleData = { + title: _metadata.filename || _metadata.title, + href: _metadata.href || _metadata.roHref, + password: _metadata.password, + channel: _metadata.channel, + }; var parsed = Hash.parsePadUrl(_metadata.href || _metadata.roHref); - common.openURL(Hash.hashToHref('', parsed.type)); - // We need to restore sessionStorage for the next time we want to create a pad from this tab - // NOTE: the 100ms timeout is to fix a race condition in firefox where sessionStorage - // would be deleted before the new tab was created - setTimeout(function () { - common.sessionStorage.put(Constants.newPadFileData, '', function () {}); - common.sessionStorage.put(Constants.newPadPathKey, '', function () {}); - common.sessionStorage.put(Constants.newPadTeamKey, '', function () {}); - }, 100); - }); + openIn(parsed.type, path, APP.team, _simpleData); + })(); } else if ($this.hasClass('cp-app-drive-context-openincode')) { if (paths.length !== 1) { return; } @@ -4264,23 +4259,20 @@ define([ password: metadata.password, channel: metadata.channel, }; - nThen(function (waitFor) { - common.sessionStorage.put(Constants.newPadFileData, JSON.stringify(simpleData), waitFor()); - common.sessionStorage.put(Constants.newPadPathKey, currentPath, waitFor()); - common.sessionStorage.put(Constants.newPadTeamKey, APP.team, waitFor()); - }).nThen(function () { - common.openURL('/code/'); - // We need to restore sessionStorage for the next time we want to create a pad from this tab - // NOTE: the 100ms timeout is to fix a race condition in firefox where sessionStorage - // would be deleted before the new tab was created - setTimeout(function () { - common.sessionStorage.put(Constants.newPadFileData, '', function () {}); - common.sessionStorage.put(Constants.newPadPathKey, '', function () {}); - common.sessionStorage.put(Constants.newPadTeamKey, '', function () {}); - }, 100); - }); + (function () { + var path = currentPath; + if (path[0] !== ROOT) { path = [ROOT]; } + var _metadata = manager.getFileData(el); + var _simpleData = { + title: _metadata.filename || _metadata.title, + href: _metadata.href || _metadata.roHref, + password: _metadata.password, + channel: _metadata.channel, + }; + var parsed = Hash.parsePadUrl(_metadata.href || _metadata.roHref); + openIn('code', path, APP.team, _simpleData); + })(); } - else if ($this.hasClass('cp-app-drive-context-expandall') || $this.hasClass('cp-app-drive-context-collapseall')) { if (paths.length !== 1) { return; } @@ -4482,12 +4474,7 @@ define([ else if ($this.hasClass("cp-app-drive-context-newdoc")) { var ntype = $this.data('type') || 'pad'; var path2 = manager.isPathIn(currentPath, [TRASH]) ? '' : currentPath; - nThen(function (waitFor) { - common.sessionStorage.put(Constants.newPadPathKey, path2, waitFor()); - common.sessionStorage.put(Constants.newPadTeamKey, APP.team, waitFor()); - }).nThen(function () { - common.openURL('/' + ntype + '/'); - }); + openIn(ntype, path2, APP.team); } else if ($this.hasClass("cp-app-drive-context-properties")) { if (type === 'trash') { diff --git a/www/common/notifications.js b/www/common/notifications.js index 44125ed71..1686b87f9 100644 --- a/www/common/notifications.js +++ b/www/common/notifications.js @@ -108,21 +108,17 @@ define([ return Messages._getKey(key, [name, title, teamName]); }; content.handler = function() { - var todo = function() { - common.openURL(msg.content.href); - defaultDismiss(common, data)(); - }; - nThen(function(waitFor) { - if (msg.content.isTemplate) { - common.sessionStorage.put(Constants.newPadPathKey, ['template'], waitFor()); - } - if (teamNotification) { - common.sessionStorage.put(Constants.newPadTeamKey, teamNotification, waitFor()); - } - common.sessionStorage.put('newPadPassword', msg.content.password || '', waitFor()); - }).nThen(function() { - todo(); + var obj = JSON.stringify({ + p: msg.content.isTemplate ? ['template'] : undefined, + t: teamNotification || undefined, + pw: msg.content.password || '' }); + var str = encodeURIComponent(obj); + var parsed = Hash.parsePadUrl(msg.content.href); + var opts = parsed.getOptions(); + opts.newPadOpts = str; + common.openURL(parsed.getUrl(opts)); + defaultDismiss(common, data)(); }; if (!content.archived) { content.dismissHandler = defaultDismiss(common, data); diff --git a/www/common/sframe-common-outer.js b/www/common/sframe-common-outer.js index aebafa834..e25be3f60 100644 --- a/www/common/sframe-common-outer.js +++ b/www/common/sframe-common-outer.js @@ -26,7 +26,7 @@ define([ }; var AppConfig; var Test; - var password; + var password, newPadPassword; var initialPathInDrive; var burnAfterReading; @@ -202,15 +202,47 @@ define([ } // Rendered (maybe hidden) hash var renderedParsed = Utils.Hash.parsePadUrl(window.location.href); - var ohc = window.onhashchange; - window.onhashchange = function () {}; - window.location.href = renderedParsed.getUrl(opts); - window.onhashchange = ohc; - ohc({reset: true}); + Cryptpad.setTabHref(renderedParsed.getUrl(opts)); } })); }; + // New pad options + if (parsed.hashData && parsed.hashData.newPadOpts) { + try { + var newPad = JSON.parse(decodeURIComponent(parsed.hashData.newPadOpts)); + Cryptpad.initialTeam = newPad.t; + Cryptpad.initialPath = newPad.p; + newPadPassword = newPad.pw; + if (newPad.d) { + Cryptpad.fromFileData = newPad.d; + var _parsed1 = Utils.Hash.parsePadUrl(Cryptpad.fromFileData.href); + if (_parsed1.hashData.type === 'pad' && _parsed1.type !== parsed.type) { + delete Cryptpad.fromFileData; + } + } + } catch (e) { + console.error(e, parsed.hashData.newPadOpts); + } + delete parsed.hashData.newPadOpts; + + // If it's a new pad, don't check password + if (!Object.keys(parsed.hashData).length) { + delete parsed.hashData; + parsed.hash = ''; + currentPad.hash = ''; + Cryptpad.setTabHash(''); + return void todo(); + } + // Otherwise, existing pad (new for us) + var opts = parsed.getOptions(); + delete opts.newPadOpts; + parsed = Utils.Hash.parsePadUrl(parsed.getUrl(opts)); + currentPad.hash = parsed.hash; + Cryptpad.setTabHash(parsed.hash); + } + + if (!parsed.hashData) { // No hash, no need to check for a password return void todo(); } @@ -340,9 +372,8 @@ define([ password = val; }), parsed.getUrl()); }).nThen(function (w) { - if (!password && !stored && sessionStorage.newPadPassword) { - passwordCfg.value = sessionStorage.newPadPassword; - delete sessionStorage.newPadPassword; + if (!password && !stored && newPadPassword) { + passwordCfg.value = newPadPassword; } if (parsed.type === "file") { @@ -362,7 +393,7 @@ define([ waitFor.abort(); return; } - if (!isNew) { return void todo(); } + if (!e && !isNew) { return void todo(); } if (parsed.hashData.mode === 'view' && (password || !parsed.hashData.password)) { // Error, wrong password stored, the view seed has changed with the password // password will never work @@ -513,18 +544,10 @@ define([ sframeChan.onReg('EV_METADATA_UPDATE', updateMeta); Utils.LocalStore.onLogin(function () { - var ohc = window.onhashchange; - window.onhashchange = function () {}; - window.location.hash = currentPad.hash; - window.onhashchange = ohc; - ohc({reset: true}); + Cryptpad.setTabHash(currentPad.hash); }); Utils.LocalStore.onLogout(function () { - var ohc = window.onhashchange; - window.onhashchange = function () {}; - window.location.hash = currentPad.hash; - window.onhashchange = ohc; - ohc({reset: true}); + Cryptpad.setTabHash(currentPad.hash); sframeChan.event('EV_LOGOUT'); }); @@ -1168,11 +1191,7 @@ define([ var hiddenParsed = Utils.Hash.parsePadUrl(window.location.href); // Update the hash in the address bar - var ohc = window.onhashchange; - window.onhashchange = function () {}; - window.location.href = hiddenParsed.getUrl(opts); - window.onhashchange = ohc; - ohc({reset: true}); + Cryptpad.setTabHref(hiddenParsed.getUrl(opts)); }); @@ -1519,11 +1538,7 @@ define([ // in the address bar Cryptpad.padRpc.onChannelDeleted.reg(function (channel) { if (channel !== secret.channel) { return; } - var ohc = window.onhashchange; - window.onhashchange = function () {}; - window.location.href = currentPad.href; - window.onhashchange = ohc; - ohc({reset: true}); + Cryptpad.setTabHref(currentPad.href); }); // Join the netflux channel @@ -1607,13 +1622,9 @@ define([ Utils.crypto = Utils.Crypto.createEncryptor(Utils.secret.keys); // Update the hash in the address bar - var ohc = window.onhashchange; - window.onhashchange = function () {}; - window.location.hash = newHash; currentPad.hash = newHash; currentPad.href = '/' + parsed.type + '/#' + newHash; - window.onhashchange = ohc; - ohc({reset: true}); + Cryptpad.setTabHash(newHash); // Update metadata values and send new metadata inside parsed = Utils.Hash.parsePadUrl(currentPad.href); From eacfffed83b312baf1f4f7b9f75ef8015acb4a6c Mon Sep 17 00:00:00 2001 From: yflory Date: Thu, 29 Oct 2020 15:10:39 +0100 Subject: [PATCH 10/21] Fix issue newPadPath with new templates --- www/common/common-ui-elements.js | 14 ++++++++------ www/common/sframe-common-outer.js | 3 +++ www/secureiframe/main.js | 9 ++++++++- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index 8b9415220..27aef1960 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -2269,12 +2269,14 @@ define([ icon: h('span.cptools.cptools-new-template') }); } - allData.unshift({ - name: Messages.creation_noTemplate, - id: 0, - //icon: h('span.fa.fa-file') - icon: UI.getFileIcon({type: type}) - }); + if (!privateData.newTemplate) { + allData.unshift({ + name: Messages.creation_noTemplate, + id: 0, + //icon: h('span.fa.fa-file') + icon: UI.getFileIcon({type: type}) + }); + } var redraw = function (index) { if (index < 0) { i = 0; } else if (index > allData.length - 1) { return; } diff --git a/www/common/sframe-common-outer.js b/www/common/sframe-common-outer.js index 7170814d8..ebf15152b 100644 --- a/www/common/sframe-common-outer.js +++ b/www/common/sframe-common-outer.js @@ -494,6 +494,8 @@ define([ fileHost: ApiConfig.fileHost, readOnly: readOnly, isTemplate: isTemplate, + newTemplate: Array.isArray(Cryptpad.initialPath) + && Cryptpad.initialPath[0] === "template", feedbackAllowed: Utils.Feedback.state, isPresent: parsed.hashData && parsed.hashData.present, isEmbed: parsed.hashData && parsed.hashData.embed, @@ -1659,6 +1661,7 @@ define([ nThen(function(waitFor) { if (data.templateId) { if (data.templateId === -1) { + isTemplate = true; initialPathInDrive = ['template']; return; } diff --git a/www/secureiframe/main.js b/www/secureiframe/main.js index eca166592..060248097 100644 --- a/www/secureiframe/main.js +++ b/www/secureiframe/main.js @@ -74,6 +74,7 @@ define([ }; window.addEventListener('message', whenReady); }).nThen(function () { + var isTemplate = config.data.isTemplate; var updateMeta = function () { //console.log('EV_METADATA_UPDATE'); var metaObj; @@ -85,6 +86,12 @@ define([ } metaObj = n; })); + if (typeof(isTemplate) === "undefined") { + Cryptpad.isTemplate(currentPad.href, waitFor(function (err, t) { + if (err) { console.log(err); } + isTemplate = t; + })); + } }).nThen(function (/*waitFor*/) { metaObj.doc = {}; var additionalPriv = { @@ -96,7 +103,7 @@ define([ feedbackAllowed: Utils.Feedback.state, hashes: config.data.hashes, password: config.data.password, - isTemplate: config.data.isTemplate, + isTemplate: isTemplate, file: config.data.file, }; for (var k in additionalPriv) { metaObj.priv[k] = additionalPriv[k]; } From 3f9c2bc96048f5a0faae2fbd2fc47140962e563a Mon Sep 17 00:00:00 2001 From: Weblate Date: Thu, 29 Oct 2020 16:48:09 +0100 Subject: [PATCH 11/21] Translated using Weblate (French) Currently translated at 100.0% (1369 of 1369 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/fr/ --- www/common/translations/messages.fr.json | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/www/common/translations/messages.fr.json b/www/common/translations/messages.fr.json index ce19c96ad..7d8a84efb 100644 --- a/www/common/translations/messages.fr.json +++ b/www/common/translations/messages.fr.json @@ -1459,5 +1459,11 @@ "admin_limitUser": "Clé publique de l'utilisateur", "fm_shareFolderPassword": "Protéger ce dossier avec un mot de passe (optionnel)", "access_destroyPad": "Détruire ce document ou dossier définitivement", - "fm_deletedFolder": "Dossier supprimé" + "fm_deletedFolder": "Dossier supprimé", + "loading_state_5": "Reconstruction du document", + "loading_state_4": "Chargement des équipes", + "loading_state_3": "Chargement des dossiers partagés", + "loading_state_2": "Mise à jour du contenu", + "loading_state_1": "Chargement du drive", + "loading_state_0": "Construction de l'interface" } From 2940fa6a0e793b395272f680d20f3f8b16144fec Mon Sep 17 00:00:00 2001 From: Weblate Date: Thu, 29 Oct 2020 16:48:09 +0100 Subject: [PATCH 12/21] Translated using Weblate (English) Currently translated at 100.0% (1369 of 1369 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 100.0% (1368 of 1368 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 100.0% (1367 of 1367 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 100.0% (1366 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 100.0% (1365 of 1365 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 100.0% (1364 of 1364 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ --- www/common/translations/messages.json | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/www/common/translations/messages.json b/www/common/translations/messages.json index 010287444..e3b84adb7 100644 --- a/www/common/translations/messages.json +++ b/www/common/translations/messages.json @@ -1459,5 +1459,11 @@ "admin_limitUser": "User's public key", "fm_deletedFolder": "Deleted folder", "access_destroyPad": "Destroy this document or folder permanently", - "fm_shareFolderPassword": "Protect this folder with a password (optional)" + "fm_shareFolderPassword": "Protect this folder with a password (optional)", + "loading_state_0": "Build interface", + "loading_state_1": "Load drive", + "loading_state_2": "Update content", + "loading_state_3": "Load shared folders", + "loading_state_4": "Load Teams", + "loading_state_5": "Reconstruct document" } From 14f785aa5eab28668e8cbcfdc6478e3b612b8de2 Mon Sep 17 00:00:00 2001 From: Weblate Date: Thu, 29 Oct 2020 16:48:10 +0100 Subject: [PATCH 13/21] Translated using Weblate (Finnish) Currently translated at 100.0% (1363 of 1363 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/fi/ --- www/common/translations/messages.fi.json | 69 +++++++++++++++++++++--- 1 file changed, 62 insertions(+), 7 deletions(-) diff --git a/www/common/translations/messages.fi.json b/www/common/translations/messages.fi.json index 3b5835ff7..fe4ee1f64 100644 --- a/www/common/translations/messages.fi.json +++ b/www/common/translations/messages.fi.json @@ -188,12 +188,12 @@ "help_button": "Ohje", "historyText": "Historia", "historyButton": "Näytä asiakirjan historia", - "history_next": "Uudempi versio", - "history_prev": "Vanhempi versio", + "history_next": "Seuraava versio", + "history_prev": "Edellinen versio", "history_loadMore": "Lataa lisää historiatietoja", "history_closeTitle": "Sulje historia", "history_restoreTitle": "Palauta asiakirjan valittu versio", - "history_restorePrompt": "Oletko varma, että haluat korvata asiakirjan nykyisen version esitetyllä versiolla?", + "history_restorePrompt": "Oletko varma, että haluat korvata asiakirjan tämänhetkisen version näytetyllä versiolla?", "history_restoreDone": "Asiakirja palautettu", "history_version": "Versio:", "openLinkInNewTab": "Avaa linkki uuteen välilehteen", @@ -452,7 +452,7 @@ "settings_backupHint": "Varmuuskopioi tai palauta CryptDrivesi sisältö kokonaisuudessaan. Varmuuskopio ei sisällä padiesi sisältöä, ainoastaan niiden käyttöön tarvittavat avaimet.", "settings_backup": "Varmuuskopioi", "settings_restore": "Palauta", - "settings_backupHint2": "Lataa kaikkien padiesi nykyinen sisältö. Padit ladataan luettavassa tiedostomuodossa, jos sellainen on saatavilla.", + "settings_backupHint2": "Lataa kaikkien asiakirjojen nykyinen sisältö tietokoneellesi. Asiakirjat ladataan muissa sovelluksissa toimivissa tiedostomuodoissa, jos se on mahdollista. Jos sopivaa tiedostomuotoa ei ole saatavilla, asiakirjat ladataan CryptPad-yhteensopivassa tiedostomuodossa.", "settings_backup2": "Lataa oma CryptDrive tietokoneellesi", "settings_backup2Confirm": "Tämä lataa kaikki CryptDrivesi padit ja tiedostot tietokoneellesi. Jos haluat jatkaa, valitse nimi ja paina OK", "settings_exportTitle": "Vie oma CryptDrive", @@ -1176,9 +1176,9 @@ "settings_safeLinksTitle": "Turvalliset linkit", "settings_cat_security": "Luottamuksellisuus", "imprint": "Oikeudellinen huomautus", - "oo_sheetMigration_anonymousEditor": "Taulukon muokkaaminen on poistettu käytöstä anonyymeille käyttäjille, kunnes rekisteröitynyt käyttäjä päivittää sen viimeisimpään versioon.", + "oo_sheetMigration_anonymousEditor": "Rekisteröitymättömät käyttäjät eivät voi muokata taulukkoa ennen kuin rekisteröitynyt käyttäjä päivittää sen viimeisimpään versioon.", "oo_sheetMigration_complete": "Päivitetty versio saatavilla, paina OK ladataksesi uudelleen.", - "oo_sheetMigration_loading": "Päivitetään taulukkoasi viimeisimpään versioon", + "oo_sheetMigration_loading": "Päivitetään taulukkoasi viimeisimpään versioon. Ole hyvä ja odota noin 1 minuutti.", "oo_exportInProgress": "Vienti menossa", "oo_importInProgress": "Tuonti menossa", "oo_invalidFormat": "Tätä tiedostoa ei voida tuoda", @@ -1404,5 +1404,60 @@ "readme_cat1_l2": "Avaa padeja CryptDrivestasi: kaksoisnapsauta padin kuvaketta avataksesi sen.", "readme_cat1_l1": "Luo padi: Siirry CryptDriveesi, napsauta {0} ja sitten {1}, ja voit luoda padin.", "readme_cat1": "Tutustu CryptDriveesi", - "readme_p2": "Tämä padi toimii pikaisena perehdytyksenä CryptPadin ominaisuuksiin - kuinka tehdä muistiinpanoja, järjestellä niitä ja tehdä yhteistyötä niiden parissa." + "readme_p2": "Tämä padi toimii pikaisena perehdytyksenä CryptPadin ominaisuuksiin - kuinka tehdä muistiinpanoja, järjestellä niitä ja tehdä yhteistyötä niiden parissa.", + "fm_shareFolderPassword": "Suojaa kansio salasanalla (vapaaehtoinen)", + "access_destroyPad": "Tuhoa tämä asiakirja tai kansio lopullisesti", + "fm_deletedFolder": "Poistettu kansio", + "admin_limitUser": "Käyttäjän julkinen avain", + "team_exportButton": "Lataa", + "team_exportHint": "Lataa kaikki tiimin CryptDriveen tallennetut asiakirjat tietokoneellesi. Asiakirjat ladataan muissa sovelluksissa toimivissa tiedostomuodoissa, jos se on mahdollista. Jos sopivaa tiedostomuotoa ei ole saatavilla, asiakirjat ladataan CryptPad-yhteensopivassa tiedostomuodossa.", + "team_exportTitle": "Lataa tiimin CryptDrive", + "admin_cat_quota": "Käyttäjätallennustila", + "admin_invalLimit": "Virheellinen arvo kiintiökentässä", + "admin_invalKey": "Virheellinen julkinen avain", + "admin_limitSetNote": "Huomautus", + "admin_limitMB": "Kiintiö (megatavuissa)", + "admin_setlimitTitle": "Ota mukautettu kiintiö käyttöön", + "admin_setlimitHint": "Aseta mukautettu tallennustilakiintiö käyttäjälle tämän julkisen avaimen avulla. Voit päivittää tai poistaa olemassaolevan tallennustilakiintiön.", + "admin_limitNote": "Huomautus: {0}", + "admin_limitPlan": "Tilaus: {0}", + "admin_defaultlimitHint": "Tallennustilakiintiö käyttäjien ja tiimien CryptDriveille, joilla ei ole erikseen määriteltyjä sääntöjä", + "admin_defaultlimitTitle": "Tallennustilakiintiö (Mt)", + "admin_getlimitsHint": "Listaa muokatut tallennustilakiintiöt, jotka ovat käytössä CryptPad-palvelimellasi.", + "admin_getlimitsTitle": "Muokatut tallennustilakiintiöt", + "admin_limit": "Nykyinen rajoitus: {0}", + "admin_setlimitButton": "Aseta rajoitus", + "admin_registrationAllow": "Avaa", + "admin_registrationButton": "Sulje", + "admin_registrationTitle": "Sulje rekisteröityminen", + "admin_registrationHint": "Älä salli uusien käyttäjien rekisteröitymistä", + "snapshots_cantMake": "Tilannevedoksen luominen epäonnistui. Yhteytesi on katkennut.", + "snapshots_notFound": "Tämä tilannevedos ei ole enää saatavilla, koska asiakirjan historia on poistettu.", + "snapshot_error_exists": "Tästä versiosta on jo olemassa tilannevedos", + "snapshots_ooPickVersion": "Valitse versio, jotta voit luoda tilannevedoksen", + "oo_version": "Versio: ", + "oo_version_latest": "Viimeisin", + "snapshots_delete": "Poista", + "oo_deletedVersion": "Tämä versio ei ole enää saatavilla historiassa.", + "snapshots_close": "Sulje", + "snapshots_restore": "Palauta", + "snapshots_open": "Avaa", + "snapshots_placeholder": "Tilannevedoksen otsikko", + "snapshots_new": "Uusi tilannevedos", + "snapshots_button": "Tilannevedokset", + "snaphot_title": "Tilannevedos", + "infobar_versionHash": "Katselet asiakirjan vanhaa versiota ({0}).", + "history_restoreDriveDone": "CryptDrive palautettu", + "history_restoreDrivePrompt": "Oletko varma, että haluat korvata CryptDriven nykyisen version valitulla versiolla?", + "history_restoreDriveTitle": "Palauta CryptDrive valitsemaasi versioon", + "history_userNext": "Seuraava laatija", + "history_fastNext": "Seuraava muokkaussessio", + "history_userPrev": "Edellinen laatija", + "history_fastPrev": "Edellinen muokkaussessio", + "share_versionHash": "Olet jakamassa valitsemasi historiaversion asiakirjastasi vain luku-tilassa. Tämä antaa myös katseluoikeuden asiakirjan kaikkiin versioihin.", + "history_shareTitle": "Jaa linkki tähän versioon", + "history_cantRestore": "Palauttaminen epäonnistui. Yhteytesi on katkennut.", + "history_close": "Sulje", + "history_restore": "Palauta", + "share_bar": "Luo linkki" } From f803c94478e54551967233180011eb75345b94cc Mon Sep 17 00:00:00 2001 From: yflory Date: Thu, 29 Oct 2020 17:14:39 +0100 Subject: [PATCH 14/21] Encrypt password before putting it in the hash --- www/common/outer/async-store.js | 1 + www/common/outer/mailbox-handlers.js | 8 +++++++- www/common/sframe-common-outer.js | 9 ++++++++- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/www/common/outer/async-store.js b/www/common/outer/async-store.js index 290147427..59deadfab 100644 --- a/www/common/outer/async-store.js +++ b/www/common/outer/async-store.js @@ -2628,6 +2628,7 @@ define([ classic: true, }; var rt = window.rt = Listmap.create(listmapConfig); + store.driveSecret = secret; store.proxy = rt.proxy; store.loggedIn = typeof(data.userHash) !== "undefined"; diff --git a/www/common/outer/mailbox-handlers.js b/www/common/outer/mailbox-handlers.js index 573879061..e5080b8e5 100644 --- a/www/common/outer/mailbox-handlers.js +++ b/www/common/outer/mailbox-handlers.js @@ -2,7 +2,8 @@ define([ '/common/common-messaging.js', '/common/common-hash.js', '/common/common-util.js', -], function (Messaging, Hash, Util) { + '/bower_components/chainpad-crypto/crypto.js', +], function (Messaging, Hash, Util, Crypto) { // Random timeout between 10 and 30 times your sync time (lag + chainpad sync) var getRandomTimeout = function (ctx) { @@ -221,6 +222,11 @@ define([ toRemove = old.data; } + if (content.password) { + var key = ctx.store.driveSecret.keys.cryptKey; + content.password = Crypto.encrypt(content.password, key); + } + // Update the data channels[channel] = { mode: mode, diff --git a/www/common/sframe-common-outer.js b/www/common/sframe-common-outer.js index ebf15152b..df1251846 100644 --- a/www/common/sframe-common-outer.js +++ b/www/common/sframe-common-outer.js @@ -213,7 +213,14 @@ define([ var newPad = JSON.parse(decodeURIComponent(parsed.hashData.newPadOpts)); Cryptpad.initialTeam = newPad.t; Cryptpad.initialPath = newPad.p; - newPadPassword = newPad.pw; + if (newPad.pw) { + try { + var uHash = Utils.LocalStore.getUserHash(); + var uSecret = Utils.Hash.getSecrets('drive', uHash); + var uKey = uSecret.keys.cryptKey; + newPadPassword = Crypto.decrypt(newPad.pw, uKey); + } catch (e) { console.error(e); } + } if (newPad.d) { Cryptpad.fromFileData = newPad.d; var _parsed1 = Utils.Hash.parsePadUrl(Cryptpad.fromFileData.href); From db1973131f280fdefa4ede71fa83aba4736f4359 Mon Sep 17 00:00:00 2001 From: ansuz Date: Fri, 30 Oct 2020 13:44:51 +0530 Subject: [PATCH 15/21] remove hardcoded translations --- customize.dist/loading.js | 7 ------- 1 file changed, 7 deletions(-) diff --git a/customize.dist/loading.js b/customize.dist/loading.js index 525f58e45..4f8b79125 100644 --- a/customize.dist/loading.js +++ b/customize.dist/loading.js @@ -278,14 +278,7 @@ button.primary:hover{ ].join(''); var built = false; - // XXX var types = ['less', 'drive', 'migrate', 'sf', 'team', 'pad', 'end']; - Messages.loading_state_0 = "Less"; - Messages.loading_state_1 = "Drive"; - Messages.loading_state_2 = "Migrate"; - Messages.loading_state_3 = "SF"; - Messages.loading_state_4 = "Team"; - Messages.loading_state_5 = "Pad"; var current; var makeList = function (data) { var c = types.indexOf(data.type); From e7b06ee0c9466c8dbe24805c57022e6b45bd9303 Mon Sep 17 00:00:00 2001 From: ansuz Date: Fri, 30 Oct 2020 14:06:48 +0530 Subject: [PATCH 16/21] remove unnecessary test comparing throttle implementations --- scripts/tests/throttle-test.js | 34 ---------------------------------- 1 file changed, 34 deletions(-) delete mode 100644 scripts/tests/throttle-test.js diff --git a/scripts/tests/throttle-test.js b/scripts/tests/throttle-test.js deleted file mode 100644 index e84fc4a8a..000000000 --- a/scripts/tests/throttle-test.js +++ /dev/null @@ -1,34 +0,0 @@ -var Util = require("../../lib/common-util"); - -(function (throttle) { - var last = 0; - var last_call = 0; - var f = Util.throttle(function (boop) { - var now = +new Date(); - if (last) { - console.log("last execution was %sms ago", now - last); - } else { - console.log("this is the first execution"); - } - last = now; - - //console.log('time of execution:', now); - console.log(boop); - }, 1000); - - [150, 250, 580, 850, 1500, 2200, 3990, 5000].forEach(function (delay) { - setTimeout(function () { - var now = +new Date(); - - if (last_call) { - console.log("last call was %sms ago", now - last_call); - } - - last_call = now; - //console.log("time of call for delay(%s):", delay, now); - f(delay); - }, delay); - }); -}(Util.throttle2)); - - From e995ea4c72fdbb84fd789862ff7e4e91aec02a1d Mon Sep 17 00:00:00 2001 From: Weblate Date: Fri, 30 Oct 2020 12:31:44 +0100 Subject: [PATCH 17/21] Translated using Weblate (English) Currently translated at 100.0% (1371 of 1371 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 100.0% (1370 of 1370 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ --- www/common/translations/messages.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/www/common/translations/messages.json b/www/common/translations/messages.json index e3b84adb7..fa96fc5a7 100644 --- a/www/common/translations/messages.json +++ b/www/common/translations/messages.json @@ -1465,5 +1465,7 @@ "loading_state_2": "Update content", "loading_state_3": "Load shared folders", "loading_state_4": "Load Teams", - "loading_state_5": "Reconstruct document" + "loading_state_5": "Reconstruct document", + "tag_add": "Add", + "tag_edit": "Edit" } From 958f8becc2e9abd458f8687b793a6822d5195387 Mon Sep 17 00:00:00 2001 From: ansuz Date: Fri, 30 Oct 2020 17:03:51 +0530 Subject: [PATCH 18/21] remove hardcoded translations and resolved notes --- www/common/common-interface.js | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/www/common/common-interface.js b/www/common/common-interface.js index d423b48ee..6d682afa7 100644 --- a/www/common/common-interface.js +++ b/www/common/common-interface.js @@ -281,12 +281,10 @@ define([ var $root = $t.parent(); - Messages.add = "Add"; // XXX - Messages.edit = "Edit"; // XXX var $input = $root.find('.token-input'); var $button = $(h('button.btn.btn-primary', [ h('i.fa.fa-plus'), - h('span', Messages.add) + h('span', Messages.tag_add) ])); @@ -311,7 +309,7 @@ define([ } $form.append($input); $form.append($button); - if (isEdit) { $button.find('span').text(Messages.edit); } + if (isEdit) { $button.find('span').text(Messages.tag_edit); } else { $button.find('span').text(Messages.add); } $container.append($form); $input.focus(); @@ -941,8 +939,6 @@ define([ $loading.css('display', ''); $loading.removeClass('cp-loading-hidden'); if (config.newProgress) { - // XXX re-add progress bar for step 6 after password prompt for PPP - // XXX also burn after reading var progress = h('div.cp-loading-progress', [ h('p.cp-loading-progress-list'), h('p.cp-loading-progress-container') From f3d2fc6ad586991afd349e7e04c7fdd3c360b3f6 Mon Sep 17 00:00:00 2001 From: yflory Date: Fri, 30 Oct 2020 15:00:12 +0100 Subject: [PATCH 19/21] Stop using sessionStorage for login redirect and new pad options --- customize.dist/login.js | 31 +++++++-- customize.dist/pages/features.js | 8 --- customize.dist/pages/index.js | 8 ++- www/common/common-hash.js | 97 +++++++++++++++++++++++----- www/common/common-ui-elements.js | 46 +++---------- www/common/cryptpad-common.js | 20 ++---- www/common/drive-ui.js | 19 ++---- www/common/notifications.js | 13 ++-- www/common/onlyoffice/inner.js | 8 +-- www/common/outer/mailbox-handlers.js | 5 ++ www/common/sframe-common-outer.js | 65 +++++++++++-------- www/common/sframe-common.js | 9 +-- www/common/toolbar.js | 8 +-- www/debug/main.js | 7 +- www/drive/main.js | 27 ++++---- www/file/inner.js | 4 +- www/profile/inner.js | 8 +-- www/secureiframe/main.js | 6 -- www/teams/inner.js | 12 +--- 19 files changed, 207 insertions(+), 194 deletions(-) diff --git a/customize.dist/login.js b/customize.dist/login.js index 35121f113..d07d4c4c3 100644 --- a/customize.dist/login.js +++ b/customize.dist/login.js @@ -28,6 +28,19 @@ define([ }; var Nacl = window.nacl; + + var redirectTo = '/drive/'; + var setRedirectTo = function () { + var parsed = Hash.parsePadUrl(window.location.href); + if (parsed.hashData && parsed.hashData.newPadOpts) { + var newPad = Hash.decodeDataOptions(parsed.hashData.newPadOpts); + redirectTo = newPad.href; + } + }; + if (window.location.hash) { + setRedirectTo(); + } + var allocateBytes = Exports.allocateBytes = function (bytes) { var dispense = Cred.dispenser(bytes); @@ -118,11 +131,11 @@ define([ }; var setMergeAnonDrive = function () { - sessionStorage.migrateAnonDrive = 1; + Exports.mergeAnonDrive = 1; }; var setCreateReadme = function () { - sessionStorage.createReadme = 1; + Exports.createReadme = 1; }; Exports.loginOrRegister = function (uname, passwd, isRegister, shouldImport, cb) { @@ -416,12 +429,20 @@ define([ }); }; Exports.redirect = function () { - if (sessionStorage.redirectTo) { - var h = sessionStorage.redirectTo; + if (redirectTo) { + var h = redirectTo; + var loginOpts = {}; + if (Exports.mergeAnonDrive) { + loginOpts.mergeAnonDrive = 1; + } + if (Exports.createReadme) { + loginOpts.createReadme = 1; + } + h = Hash.getLoginURL(h, loginOpts); + var parser = document.createElement('a'); parser.href = h; if (parser.origin === window.location.origin) { - delete sessionStorage.redirectTo; window.location.href = h; return; } diff --git a/customize.dist/pages/features.js b/customize.dist/pages/features.js index 6403ec36a..56bb29664 100644 --- a/customize.dist/pages/features.js +++ b/customize.dist/pages/features.js @@ -22,14 +22,6 @@ define([ target: '_blank', rel: 'noopener noreferrer' }, h('button.cp-features-register-button', Msg.features_f_subscribe)); - /*$(premiumButton).click(function (e) { - if (LocalStore.isLoggedIn()) { return; } - // Not logged in: go to /login with a redirect to this page - e.preventDefault(); - e.stopPropagation(); - sessionStorage.redirectTo = '/features.html'; - window.location.href = '/login/'; - });*/ var anonymousFeatures = h('div.col-12.col-sm-4.cp-anon-user',[ diff --git a/customize.dist/pages/index.js b/customize.dist/pages/index.js index 300637748..c718b363f 100644 --- a/customize.dist/pages/index.js +++ b/customize.dist/pages/index.js @@ -4,12 +4,13 @@ define([ '/common/hyperscript.js', '/common/common-feedback.js', '/common/common-interface.js', + '/common/common-hash.js', '/common/textFit.min.js', '/customize/messages.js', '/customize/application_config.js', '/common/outer/local-store.js', '/customize/pages.js' -], function ($, Config, h, Feedback, UI, TextFit, Msg, AppConfig, LocalStore, Pages) { +], function ($, Config, h, Feedback, UI, Hash, TextFit, Msg, AppConfig, LocalStore, Pages) { var urlArgs = Config.requireConf.urlArgs; var isAvailableType = function (x) { @@ -46,8 +47,9 @@ define([ var href = '/'+ x[0] +'/'; var attr = isEnabled ? { href: href } : { onclick: function () { - sessionStorage.redirectTo = href; - window.location.href = '/login/'; + var href = Hash.hashToHref('', 'login'); + var url = Hash.getNewPadURL(href, { href: href }); + window.location.href = url; } }; if (!isEnabled) { diff --git a/www/common/common-hash.js b/www/common/common-hash.js index ff8764da4..06a1d7fef 100644 --- a/www/common/common-hash.js +++ b/www/common/common-hash.js @@ -169,6 +169,17 @@ Version 1 /code/#/1/edit/3Ujt4F2Sjnjbis6CoYWpoQ/usn4+9CqVja8Q7RZOGTfRgqI */ + var getLoginOpts = function (hashArr) { + var k; + // Check if we have a ownerKey for this pad + hashArr.some(function (data) { + if (/^login=/.test(data)) { + k = data.slice(6); + return true; + } + }); + return k || ''; + }; var getNewPadOpts = function (hashArr) { var k; // Check if we have a ownerKey for this pad @@ -214,28 +225,51 @@ Version 1 parsed.embed = options.indexOf('embed') !== -1; parsed.versionHash = getVersionHash(options); parsed.newPadOpts = getNewPadOpts(options); + parsed.loginOpts = getLoginOpts(options); parsed.ownerKey = getOwnerKey(options); }; + // Version 4: only login or newpad options, smae for all the apps + if (hashArr[1] && hashArr[1] === '4') { + parsed.getHash = function (opts) { + if (!opts || !Object.keys(opts).length) { return ''; } + var hash = '/4/'; + if (opts.newPadOpts) { hash += 'newpad=' + opts.newPadOpts + '/'; } + if (opts.loginOpts) { hash += 'login=' + opts.loginOpts + '/'; } + return hash; + }; + parsed.getOptions = function () { + var options = {}; + if (parsed.newPadOpts) { options.newPadOpts = parsed.newPadOpts; } + if (parsed.loginOpts) { options.loginOpts = parsed.loginOpts; } + return options; + }; + + parsed.version = 4; + options = hashArr.slice(2); + addOptions(); + + return parsed; + } + + // The other versions depends on the type if (['media', 'file', 'user', 'invite'].indexOf(type) === -1) { parsed.type = 'pad'; - parsed.getHash = function () { return hash; }; + parsed.getHash = function () { + return hash; + }; parsed.getOptions = function () { return { embed: parsed.embed, present: parsed.present, ownerKey: parsed.ownerKey, versionHash: parsed.versionHash, + newPadOpts: parsed.newPadOpts, + loginOpts: parsed.loginOpts, password: parsed.password }; }; - if (/^\/newpad=/.test(hash)) { - return { - newPadOpts: hash.slice(8, -1) - }; - } - if (hash.slice(0,1) !== '/' && hash.length >= 56) { // Version 0 // Old hash parsed.channel = hash.slice(0, 32); @@ -256,9 +290,8 @@ Version 1 if (versionHash) { hash += 'hash=' + Crypto.b64RemoveSlashes(versionHash) + '/'; } - if (opts.newPadOpts) { - hash += 'newpad=' + opts.newPadOpts + '/'; - } + if (opts.newPadOpts) { hash += 'newpad=' + opts.newPadOpts + '/'; } + if (opts.loginOpts) { hash += 'login=' + opts.loginOpts + '/'; } return hash; }; @@ -306,6 +339,8 @@ Version 1 embed: parsed.embed, present: parsed.present, ownerKey: parsed.ownerKey, + newPadOpts: parsed.newPadOpts, + loginOpts: parsed.loginOpts, password: parsed.password }; }; @@ -317,6 +352,8 @@ Version 1 if (parsed.password || opts.password) { hash += 'p/'; } if (opts.embed) { hash += 'embed/'; } if (opts.present) { hash += 'present/'; } + if (opts.newPadOpts) { hash += 'newpad=' + opts.newPadOpts + '/'; } + if (opts.loginOpts) { hash += 'login=' + opts.loginOpts + '/'; } return hash; }; @@ -389,18 +426,26 @@ Version 1 var idx; + // When we start without a hash, use version 4 links to add login or newpad options + var getHash = function (opts) { + if (!opts || !Object.keys(opts).length) { return ''; } + var hash = '/4/'; + if (opts.newPadOpts) { hash += 'newpad=' + opts.newPadOpts + '/'; } + if (opts.loginOpts) { hash += 'login=' + opts.loginOpts + '/'; } + return hash; + }; ret.getUrl = function (options) { options = options || {}; var url = '/'; if (!ret.type) { return url; } url += ret.type + '/'; // New pad with options: append the options to the hash - if (!ret.hashData && options.newPadOpts) { - return url + '#/newpad=' + options.newPadOpts + '/'; + if (!ret.hashData && options && Object.keys(options).length) { + return url + '#' + getHash(options); } if (!ret.hashData) { return url; } - if (ret.hashData.type !== 'pad') { return url + '#' + ret.hash; } - if (ret.hashData.version === 0) { return url + '#' + ret.hash; } + //if (ret.hashData.version === 0) { return url + '#' + ret.hash; } + //if (ret.hashData.type !== 'pad') { return url + '#' + ret.hash; } var hash = ret.hashData.getHash(options); url += '#' + hash; return url; @@ -549,7 +594,6 @@ Version 1 secret = JSON.parse(JSON.stringify(secret)); if (!secret.keys && !secret.key) { - console.error('e'); return hashes; } else if (!secret.keys) { secret.keys = {}; @@ -615,6 +659,29 @@ Version 1 return true; }; + Hash.decodeDataOptions = function (opts) { + var b64 = decodeURIComponent(opts); + var str = Nacl.util.encodeUTF8(Nacl.util.decodeBase64(b64)); + return JSON.parse(str); + }; + Hash.encodeDataOptions = function (opts) { + var str = JSON.stringify(opts); + var b64 = Nacl.util.encodeBase64(Nacl.util.decodeUTF8(str)); + return encodeURIComponent(b64); + }; + Hash.getNewPadURL = function (href, opts) { + var parsed = Hash.parsePadUrl(href); + var options = parsed.getOptions(); + options.newPadOpts = Hash.encodeDataOptions(opts); + return parsed.getUrl(options); + }; + Hash.getLoginURL = function (href, opts) { + var parsed = Hash.parsePadUrl(href); + var options = parsed.getOptions(); + options.loginOpts = Hash.encodeDataOptions(opts); + return parsed.getUrl(options); + }; + return Hash; }; diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index bd19bb329..c66c5cce3 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -254,20 +254,15 @@ define([ className: 'secondary', name: Messages.login_register, onClick: function () { - common.setLoginRedirect(function () { - common.gotoURL('/register/'); - }); + common.setLoginRedirect('register'); } }, { className: 'secondary', name: Messages.login_login, onClick: function () { - common.setLoginRedirect(function () { - common.gotoURL('/login/'); - }); + common.setLoginRedirect('login'); } - } - ] + }] }; } }; @@ -1787,9 +1782,7 @@ define([ attributes: {'class': 'cp-toolbar-menu-login fa fa-sign-in'}, content: h('span', Messages.login_login), action: function () { - Common.setLoginRedirect(function () { - window.parent.location = origin+'/login/'; - }); + Common.setLoginRedirect('login'); }, }); options.push({ @@ -1797,9 +1790,7 @@ define([ attributes: {'class': 'cp-toolbar-menu-register fa fa-user-plus'}, content: h('span', Messages.login_register), action: function () { - Common.setLoginRedirect(function () { - window.parent.location = origin+'/register/'; - }); + Common.setLoginRedirect('register'); }, }); } @@ -1924,8 +1915,6 @@ define([ $modal.find('.cp-modal').append($title); $modal.find('.cp-modal').append($description); - var $advanced; - var $container = $('
'); var i = 0; var types = AppConfig.availablePadTypes.filter(function (p) { @@ -1949,15 +1938,7 @@ define([ $element.attr('data-type', p); $element.click(function () { $modal.hide(); - if ($advanced && Util.isChecked($advanced)) { - common.sessionStorage.put(Constants.displayPadCreationScreen, true, function (){ - common.openURL('/' + p + '/'); - }); - return; - } - common.sessionStorage.put(Constants.displayPadCreationScreen, "", function () { - common.openURL('/' + p + '/'); - }); + common.openURL('/' + p + '/'); }); }); @@ -1982,12 +1963,6 @@ define([ } return; } - if (e.which === 32 && $advanced) { - $advanced.prop('checked', !$advanced.prop('checked')); - $modal.focus(); - e.stopPropagation(); - e.preventDefault(); - } }); @@ -2752,13 +2727,8 @@ define([ $(link).click(function (e) { e.preventDefault(); e.stopPropagation(); - if (msg.content.password) { - common.sessionStorage.put('newPadPassword', msg.content.password, function () { - common.openURL(msg.content.href); - }); - return; - } - common.openURL(msg.content.href); + var obj = { pw: msg.content.password || '' }; + common.openURL(Hash.getNewPadURL(msg.content.href, obj)); }); var div = h('div', [ diff --git a/www/common/cryptpad-common.js b/www/common/cryptpad-common.js index 3e65168a8..f98a7e049 100644 --- a/www/common/cryptpad-common.js +++ b/www/common/cryptpad-common.js @@ -1879,8 +1879,9 @@ define([ LocalStore.logout(); // redirect them to log in, and come back when they're done. - sessionStorage.redirectTo = currentPad.href; - window.location.href = '/login/'; + var href = Hash.hashToHref('', 'login'); + var url = Hash.getNewPadURL(href, { href: currentPad.href }); + window.location.href = url; }; common.startAccountDeletion = function (data, cb) { @@ -2276,12 +2277,6 @@ define([ if (data.anonHash && !cfg.userHash) { LocalStore.setFSHash(data.anonHash); } - /*if (cfg.userHash && sessionStorage) { - // copy User_hash into sessionStorage because cross-domain iframes - // on safari replaces localStorage with sessionStorage or something - sessionStorage.setItem(Constants.userHashKey, cfg.userHash); - }*/ - if (cfg.userHash) { var localToken = tryParsing(localStorage.getItem(Constants.tokenKey)); if (localToken === null) { @@ -2336,21 +2331,18 @@ define([ postMessage("DISCONNECT"); }); }).nThen(function (waitFor) { - if (sessionStorage.createReadme) { + if (common.createReadme) { var data = { driveReadme: Messages.driveReadme, driveReadmeTitle: Messages.driveReadmeTitle, }; postMessage("CREATE_README", data, waitFor(function (e) { if (e && e.error) { return void console.error(e.error); } - delete sessionStorage.createReadme; })); } }).nThen(function (waitFor) { - if (sessionStorage.migrateAnonDrive) { - common.mergeAnonDrive(waitFor(function() { - delete sessionStorage.migrateAnonDrive; - })); + if (common.migrateAnonDrive) { + common.mergeAnonDrive(waitFor()); } }).nThen(function (waitFor) { if (AppConfig.afterLogin) { diff --git a/www/common/drive-ui.js b/www/common/drive-ui.js index 08a3f1279..53e496ef4 100644 --- a/www/common/drive-ui.js +++ b/www/common/drive-ui.js @@ -1126,16 +1126,13 @@ define([ window.open(APP.origin + hiddenHref); }; var openIn = function (type, path, team, fData) { - var obj = JSON.stringify({ + var obj = { p: path, t: team, d: fData - }); - var str = encodeURIComponent(obj); - var parsed = Hash.parsePadUrl(Hash.hashToHref('', type)); - var opts = parsed.getOptions(); - opts.newPadOpts = str; - common.openURL(parsed.getUrl(opts)); + }; + var href = Hash.hashToHref('', type); + common.openURL(Hash.getNewPadURL(href, obj)); }; var refresh = APP.refresh = function () { @@ -4252,13 +4249,6 @@ define([ if (paths.length !== 1) { return; } var p = paths[0]; el = manager.find(p.path); - var metadata = manager.getFileData(el); - var simpleData = { - title: metadata.filename || metadata.title, - href: metadata.href, - password: metadata.password, - channel: metadata.channel, - }; (function () { var path = currentPath; if (path[0] !== ROOT) { path = [ROOT]; } @@ -4269,7 +4259,6 @@ define([ password: _metadata.password, channel: _metadata.channel, }; - var parsed = Hash.parsePadUrl(_metadata.href || _metadata.roHref); openIn('code', path, APP.team, _simpleData); })(); } diff --git a/www/common/notifications.js b/www/common/notifications.js index 1686b87f9..caf5bfe00 100644 --- a/www/common/notifications.js +++ b/www/common/notifications.js @@ -7,8 +7,7 @@ define([ '/common/common-util.js', '/common/common-constants.js', '/customize/messages.js', - '/bower_components/nthen/index.js' -], function($, h, Hash, UI, UIElements, Util, Constants, Messages, nThen) { +], function($, h, Hash, UI, UIElements, Util, Constants, Messages) { var handlers = {}; @@ -108,16 +107,12 @@ define([ return Messages._getKey(key, [name, title, teamName]); }; content.handler = function() { - var obj = JSON.stringify({ + var obj = { p: msg.content.isTemplate ? ['template'] : undefined, t: teamNotification || undefined, pw: msg.content.password || '' - }); - var str = encodeURIComponent(obj); - var parsed = Hash.parsePadUrl(msg.content.href); - var opts = parsed.getOptions(); - opts.newPadOpts = str; - common.openURL(parsed.getUrl(opts)); + }; + common.openURL(Hash.getNewPadURL(msg.content.href, obj)); defaultDismiss(common, data)(); }; if (!content.archived) { diff --git a/www/common/onlyoffice/inner.js b/www/common/onlyoffice/inner.js index 103381f62..14c60cc5c 100644 --- a/www/common/onlyoffice/inner.js +++ b/www/common/onlyoffice/inner.js @@ -458,15 +458,11 @@ define([ var actions = h('div', [cancel, register, login]); var modal = UI.cornerPopup(Messages.oo_login, actions, '', {alt: true}); $(register).click(function () { - common.setLoginRedirect(function () { - common.gotoURL('/register/'); - }); + common.setLoginRedirect('register'); modal.delete(); }); $(login).click(function () { - common.setLoginRedirect(function () { - common.gotoURL('/login/'); - }); + common.setLoginRedirect('login'); modal.delete(); }); $(cancel).click(function () { diff --git a/www/common/outer/mailbox-handlers.js b/www/common/outer/mailbox-handlers.js index e5080b8e5..326b4afc7 100644 --- a/www/common/outer/mailbox-handlers.js +++ b/www/common/outer/mailbox-handlers.js @@ -321,6 +321,11 @@ define([ var channel = content.channel || content.teamChannel; + if (content.password) { + var key = ctx.store.driveSecret.keys.cryptKey; + content.password = Crypto.encrypt(content.password, key); + } + if (addOwners[channel]) { return void cb(true); } addOwners[channel] = { type: box.type, diff --git a/www/common/sframe-common-outer.js b/www/common/sframe-common-outer.js index 416c25813..a5366d3fd 100644 --- a/www/common/sframe-common-outer.js +++ b/www/common/sframe-common-outer.js @@ -131,12 +131,28 @@ define([ if (sframeChan) { sframeChan.event('EV_LOADING_INFO', data); } }); + try { + var parsed = Utils.Hash.parsePadUrl(currentPad.href); + var options = parsed.getOptions(); + if (options.loginOpts) { + var loginOpts = Utils.Hash.decodeDataOptions(options.loginOpts); + if (loginOpts.createReadme) { Cryptpad.createReadme = true; } + if (loginOpts.mergeAnonDrive) { Cryptpad.migrateAnonDrive = true; } + // Remove newPadOpts from the hash + delete options.loginOpts; + currentPad.href = parsed.getUrl(options); + currentPad.hash = parsed.hashData.getHash ? parsed.hashData.getHash(options) + : ''; + } + } catch (e) { console.error(e); } + Cryptpad.ready(waitFor(), { driveEvents: cfg.driveEvents, currentPad: currentPad }); - if (window.history && window.history.replaceState && currentPad.hash) { + // Remove the login hash if needed + if (window.history && window.history.replaceState && (currentPad.hash || window.location.hash)) { var nHash = currentPad.hash; if (!/^#/.test(nHash)) { nHash = '#' + nHash; } window.history.replaceState({}, window.document.title, nHash); @@ -202,9 +218,10 @@ define([ }; // New pad options - if (parsed.hashData && parsed.hashData.newPadOpts) { + var options = parsed.getOptions(); + if (options.newPadOpts) { try { - var newPad = JSON.parse(decodeURIComponent(parsed.hashData.newPadOpts)); + var newPad = Utils.Hash.decodeDataOptions(options.newPadOpts); Cryptpad.initialTeam = newPad.t; Cryptpad.initialPath = newPad.p; if (newPad.pw) { @@ -225,22 +242,20 @@ define([ } catch (e) { console.error(e, parsed.hashData.newPadOpts); } - delete parsed.hashData.newPadOpts; + delete options.newPadOpts; + + currentPad.href = parsed.getUrl(options); + currentPad.hash = parsed.hashData.getHash ? parsed.hashData.getHash(options) + : ''; + var version = parsed.hashData.version; + parsed = Utils.Hash.parsePadUrl(currentPad.href); + Cryptpad.setTabHash(currentPad.hash); // If it's a new pad, don't check password - if (!Object.keys(parsed.hashData).length) { - delete parsed.hashData; - parsed.hash = ''; - currentPad.hash = ''; - Cryptpad.setTabHash(''); + if (version === 4) { return void todo(); } - // Otherwise, existing pad (new for us) - var opts = parsed.getOptions(); - delete opts.newPadOpts; - parsed = Utils.Hash.parsePadUrl(parsed.getUrl(opts)); - currentPad.hash = parsed.hash; - Cryptpad.setTabHash(parsed.hash); + // Otherwise, continue } @@ -460,9 +475,6 @@ define([ var defaultTitle = Utils.UserObject.getDefaultName(parsed); var edPublic, curvePublic, notifications, isTemplate; var settings = {}; - var forceCreationScreen = cfg.useCreationScreen && - sessionStorage[Utils.Constants.displayPadCreationScreen]; - delete sessionStorage[Utils.Constants.displayPadCreationScreen]; var isSafe = ['debug', 'profile', 'drive', 'teams'].indexOf(currentPad.app) !== -1; var updateMeta = function () { //console.log('EV_METADATA_UPDATE'); @@ -507,7 +519,6 @@ define([ }, isNewFile: isNewFile, isDeleted: isNewFile && currentPad.hash.length > 0, - forceCreationScreen: forceCreationScreen, password: password, channel: secret.channel, enableSF: localStorage.CryptPad_SF === "1", // TODO to remove when enabled by default @@ -635,9 +646,10 @@ define([ Cryptpad.mailbox.execCommand(data, cb); }); - sframeChan.on('Q_SET_LOGIN_REDIRECT', function (data, cb) { - sessionStorage.redirectTo = currentPad.href; - cb(); + sframeChan.on('EV_SET_LOGIN_REDIRECT', function (page) { + var href = Utils.Hash.hashToHref('', page); + var url = Utils.Hash.getNewPadURL(href, { href: currentPad.href }); + window.location.href = url; }); sframeChan.on('Q_STORE_IN_TEAM', function (data, cb) { @@ -1065,11 +1077,10 @@ define([ password: password, title: currentTitle }; - sessionStorage[Utils.Constants.newPadFileData] = JSON.stringify(data); - window.open(window.location.pathname); - setTimeout(function () { - delete sessionStorage[Utils.Constants.newPadFileData]; - }, 100); + var obj = { d: data }; + var href = window.location.pathname; + var url = Utils.Hash.getNewPadURL(href, obj); + window.open(url); }); // Messaging diff --git a/www/common/sframe-common.js b/www/common/sframe-common.js index f7a2c41c3..ffff122b5 100644 --- a/www/common/sframe-common.js +++ b/www/common/sframe-common.js @@ -307,9 +307,8 @@ define([ ctx.sframeChan.event('EV_SET_HASH', hash); }; - funcs.setLoginRedirect = function (cb) { - cb = cb || $.noop; - ctx.sframeChan.query('Q_SET_LOGIN_REDIRECT', null, cb); + funcs.setLoginRedirect = function (page) { + ctx.sframeChan.query('EV_SET_LOGIN_REDIRECT', page); }; funcs.isPresentUrl = function (cb) { @@ -758,9 +757,7 @@ define([ var mustLogin = privateData.registeredOnly; if (mustLogin) { UI.alert(Messages.mustLogin, function () { - funcs.setLoginRedirect(function () { - funcs.gotoURL('/login/'); - }); + funcs.setLoginRedirect('login'); }, {forefront: true}); return; } diff --git a/www/common/toolbar.js b/www/common/toolbar.js index 9a96039f6..78e4e91f3 100644 --- a/www/common/toolbar.js +++ b/www/common/toolbar.js @@ -773,15 +773,11 @@ MessengerUI, Messages) { ]); $msg.find('a.cp-pnp-login').click(function (ev) { ev.preventDefault(); - Common.setLoginRedirect(function () { - window.parent.location = o + '/login/'; - }); + Common.setLoginRedirect('login'); }); $msg.find('a.cp-pnp-register').click(function (ev) { ev.preventDefault(); - Common.setLoginRedirect(function () { - window.parent.location = o + '/register/'; - }); + Common.setLoginRedirect('register'); }); $('.cp-toolbar-top').append($msg); //UI.addTooltips(); diff --git a/www/debug/main.js b/www/debug/main.js index 68055b1d4..b901beec0 100644 --- a/www/debug/main.js +++ b/www/debug/main.js @@ -53,14 +53,9 @@ define([ }; window.addEventListener('message', onMsg); }).nThen(function (/*waitFor*/) { - var hash = localStorage[Constants.userHashKey]; + var hash = localStorage[Constants.userHashKey] || localStorage[Constants.fileHashKey]; var drive = hash && ('#'+hash === window.location.hash); if (!window.location.hash) { - if (!hash) { - sessionStorage.redirectTo = '/debug/'; - window.location.href = '/login/'; - return; - } drive = true; window.location.hash = hash; } else { diff --git a/www/drive/main.js b/www/drive/main.js index 8db013c0f..5eb9dbc67 100644 --- a/www/drive/main.js +++ b/www/drive/main.js @@ -46,9 +46,12 @@ define([ window.addEventListener('message', onMsg); }).nThen(function (/*waitFor*/) { var afterSecrets = function (Cryptpad, Utils, secret, cb, sframeChan) { - var _hash = hash.slice(1); - if (_hash && Utils.LocalStore.isLoggedIn()) { - // Add a shared folder! + var parsed = Utils.Hash.parsePadUrl(href); + var isSf = parsed.hashData && parsed.hashData.type === 'pad'; + if (!isSf) { return void cb(); } + + // SF and logged in: add shared folder + if (Utils.LocalStore.isLoggedIn()) { Cryptpad.addSharedFolder(null, secret, function (id) { if (id && typeof(id) === "object" && id.error) { sframeChan.event("EV_RESTRICTED_ERROR"); @@ -65,16 +68,16 @@ define([ cb(); }); return; - } else if (_hash) { - var id = Utils.Util.createRandomInteger(); - window.CryptPad_newSharedFolder = id; - var data = { - href: Utils.Hash.getRelativeHref(Cryptpad.currentPad.href), - password: secret.password - }; - return void Cryptpad.loadSharedFolder(id, data, cb); } - cb(); + + // Anon shared folder + var id = Utils.Util.createRandomInteger(); + window.CryptPad_newSharedFolder = id; + var data = { + href: Utils.Hash.getRelativeHref(Cryptpad.currentPad.href), + password: secret.password + }; + Cryptpad.loadSharedFolder(id, data, cb); }; var addRpc = function (sframeChan, Cryptpad, Utils) { sframeChan.on('EV_BURN_ANON_DRIVE', function () { diff --git a/www/file/inner.js b/www/file/inner.js index 81019d0be..b2aef53ed 100644 --- a/www/file/inner.js +++ b/www/file/inner.js @@ -231,9 +231,7 @@ define([ if (!common.isLoggedIn()) { UI.removeLoadingScreen(); return UI.alert(Messages.upload_mustLogin, function () { - common.setLoginRedirect(function () { - common.gotoURL('/login/'); - }); + common.setLoginRedirect('login'); }); } diff --git a/www/profile/inner.js b/www/profile/inner.js index cddae4611..7a872fdd0 100644 --- a/www/profile/inner.js +++ b/www/profile/inner.js @@ -611,15 +611,11 @@ define([ var actions = h('div', [cancel, register, login]); var modal = UI.cornerPopup(Messages.profile_login, actions, '', {alt: true}); $(register).click(function () { - common.setLoginRedirect(function () { - common.gotoURL('/register/'); - }); + common.setLoginRedirect('register'); modal.delete(); }); $(login).click(function () { - common.setLoginRedirect(function () { - common.gotoURL('/login/'); - }); + common.setLoginRedirect('login'); modal.delete(); }); $(cancel).click(function () { diff --git a/www/secureiframe/main.js b/www/secureiframe/main.js index 060248097..49e94a252 100644 --- a/www/secureiframe/main.js +++ b/www/secureiframe/main.js @@ -86,12 +86,6 @@ define([ } metaObj = n; })); - if (typeof(isTemplate) === "undefined") { - Cryptpad.isTemplate(currentPad.href, waitFor(function (err, t) { - if (err) { console.log(err); } - isTemplate = t; - })); - } }).nThen(function (/*waitFor*/) { metaObj.doc = {}; var additionalPriv = { diff --git a/www/teams/inner.js b/www/teams/inner.js index 2eb234b12..a75ed94db 100644 --- a/www/teams/inner.js +++ b/www/teams/inner.js @@ -1267,14 +1267,10 @@ define([ anonRegister = h('button.btn.btn-secondary', Messages.login_register), ])); $(anonLogin).click(function () { - common.setLoginRedirect(function () { - common.gotoURL('/login/'); - }); + common.setLoginRedirect('login'); }); $(anonRegister).click(function () { - common.setLoginRedirect(function () { - common.gotoURL('/register/'); - }); + common.setLoginRedirect('register'); }); waitFor.abort(); }).nThen(function () { @@ -1402,9 +1398,7 @@ define([ var hash = privateData.teamInviteHash; if (!hash && !driveAPP.loggedIn) { UI.alert(Messages.mustLogin, function () { - common.setLoginRedirect(function () { - common.gotoURL('/login/'); - }); + common.setLoginRedirect('login'); }, {forefront: true}); return; } From 86e20b7395d3e15926a21862e7b048b956fb5498 Mon Sep 17 00:00:00 2001 From: yflory Date: Fri, 30 Oct 2020 15:05:28 +0100 Subject: [PATCH 20/21] Catch errors in outer too --- www/common/boot2.js | 3 +++ www/common/sframe-common-outer.js | 3 +++ 2 files changed, 6 insertions(+) diff --git a/www/common/boot2.js b/www/common/boot2.js index fc3968fb3..30f776a25 100644 --- a/www/common/boot2.js +++ b/www/common/boot2.js @@ -43,6 +43,9 @@ define([ console.error("Require.js threw a Script Error. This probably means you're missing a dependency for CryptPad.\nIt is recommended that the admin of this server runs `bower install && bower update` to get the latest code, then modify their cache version.\nBest of luck,\nThe CryptPad Developers"); return void console.log(); } + if (window.CryptPad_loadingError) { + window.CryptPad_loadingError(e); + } throw e; }; diff --git a/www/common/sframe-common-outer.js b/www/common/sframe-common-outer.js index 6114b5d1a..3a9d532a8 100644 --- a/www/common/sframe-common-outer.js +++ b/www/common/sframe-common-outer.js @@ -123,6 +123,9 @@ define([ }); SFrameChannel.create(msgEv, postMsg, waitFor(function (sfc) { Utils.sframeChan = sframeChan = sfc; + window.CryptPad_loadingError = function (e) { + sfc.event('EV_LOADING_ERROR', e) + }; })); }); window.addEventListener('message', whenReady); From 733db7d39fd1fadb36f7537a09083c66b35a2a44 Mon Sep 17 00:00:00 2001 From: yflory Date: Fri, 30 Oct 2020 15:13:22 +0100 Subject: [PATCH 21/21] Stop using sessionStorage in CryptPad --- www/auth/index.html | 9 - www/auth/main.js | 193 --------------------- www/common/common-constants.js | 4 - www/common/onlyoffice/main.js | 2 +- www/common/outer/async-store.js | 1 - www/common/outer/local-store.js | 16 -- www/common/sframe-channel.js | 166 ------------------ www/common/sframe-common-outer.js | 9 - www/common/sframe-common.js | 9 - www/common/sframe-protocol.js | 271 ------------------------------ www/login/main.js | 6 +- www/logout/main.js | 1 - www/register/main.js | 6 +- 13 files changed, 6 insertions(+), 687 deletions(-) delete mode 100644 www/auth/index.html delete mode 100644 www/auth/main.js delete mode 100644 www/common/sframe-channel.js delete mode 100644 www/common/sframe-protocol.js diff --git a/www/auth/index.html b/www/auth/index.html deleted file mode 100644 index 685ca37c4..000000000 --- a/www/auth/index.html +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/www/auth/main.js b/www/auth/main.js deleted file mode 100644 index fcbeaf3af..000000000 --- a/www/auth/main.js +++ /dev/null @@ -1,193 +0,0 @@ -define([ - 'jquery', - '/api/config', - '/common/cryptget.js', - '/common/pinpad.js', - '/common/common-constants.js', - '/common/common-hash.js', - '/common/outer/local-store.js', - '/common/outer/login-block.js', - '/common/outer/network-config.js', - '/customize/login.js', - '/common/test.js', - '/bower_components/nthen/index.js', - '/bower_components/netflux-websocket/netflux-client.js', - '/bower_components/tweetnacl/nacl-fast.min.js' -], function ($, ApiConfig, Crypt, Pinpad, Constants, Hash, LocalStore, Block, NetConfig, Login, Test, nThen, Netflux) { - var Nacl = window.nacl; - - var signMsg = function (msg, privKey) { - var signKey = Nacl.util.decodeBase64(privKey); - var buffer = Nacl.util.decodeUTF8(msg); - return Nacl.util.encodeBase64(Nacl.sign(buffer, signKey)); - }; - - // TODO: Allow authing for any domain as long as the user clicks an "accept" button - // inside of the iframe. - var AUTHORIZED_DOMAINS = [ - /\.cryptpad\.fr$/, - /^http(s)?:\/\/localhost\:/ - ]; - - // Safari is weird about localStorage in iframes but seems to let sessionStorage slide. - localStorage[Constants.userHashKey] = localStorage[Constants.userHashKey] || - sessionStorage[Constants.userHashKey]; - - var proxy; - var rpc; - var network; - var rpcError; - var contacts = {}; - - var loadProxy = function (hash) { - nThen(function (waitFor) { - var wsUrl = NetConfig.getWebsocketURL(); - var w = waitFor(); - Netflux.connect(wsUrl).then(function (_network) { - network = _network; - w(); - }, function (err) { - rpcError = err; - console.error(err); - }); - }).nThen(function (waitFor) { - Crypt.get(hash, waitFor(function (err, val) { - if (err) { - waitFor.abort(); - console.error(err); - return; - } - try { - var parsed = JSON.parse(val); - proxy = parsed; - } catch (e) { - console.log("Can't parse user drive", e); - } - }), { - network: network - }); - }).nThen(function () { - var origin = ApiConfig.fileHost || window.location.origin; - // Get contacts and extract their avatar channel and key - var getData = function (obj, href) { - var parsed = Hash.parsePadUrl(href); - if (!parsed || parsed.type !== "file") { return; } - var secret = Hash.getSecrets('file', parsed.hash); - if (!secret.keys || !secret.channel) { return; } - obj.avatarKey = Hash.encodeBase64(secret.keys && secret.keys.cryptKey); - obj.avatarSrc = origin + Hash.getBlobPathFromHex(secret.channel); - }; - contacts.teams = proxy.teams || {}; - contacts.friends = proxy.friends || {}; - Object.keys(contacts.friends).map(function (key) { - var friend = contacts.friends[key]; - if (!friend) { return; } - var ret = { - edPublic: friend.edPublic, - name: friend.displayName, - }; - getData(ret, friend.avatar); - contacts.friends[key] = ret; - }); - Object.keys(contacts.teams).map(function (key) { - var team = contacts.teams[key]; - if (!team) { return; } - var avatar = team.metadata && team.metadata.avatar; - var ret = { - edPublic: team.keys && team.keys.drive && team.keys.drive.edPublic, - name: team.metadata && team.metadata.name - }; - getData(ret, avatar); - contacts.teams[key] = ret; - }); - contacts.origin = window.location.origin; - }).nThen(function (waitFor) { - if (!network) { return void waitFor.abort(); } - Pinpad.create(network, proxy, waitFor(function (e, call) { - if (e) { - rpcError = e; - return void waitFor.abort(); - } - rpc = call; - })); - }).nThen(function () { - Test(function () { - // This is only here to maybe trigger an error. - window.drive = proxy['drive']; - Test.passed(); - }); - }); - }; - - var whenReady = function (cb) { - if (proxy && (rpc || rpcError)) { return void cb(); } - console.log('CryptPad not ready...'); - setTimeout(function () { - whenReady(cb); - }, 100); - }; - - $(window).on("message", function (jqe) { - var evt = jqe.originalEvent; - var data = JSON.parse(evt.data); - var domain = evt.origin; - var srcWindow = evt.source; - var ret = { txid: data.txid }; - console.log('CP receiving', data); - if (data.cmd === 'PING') { - ret.res = 'PONG'; - } else if (data.cmd === 'LOGIN') { - Login.loginOrRegister(data.data.name, data.data.password, false, false, function (err) { - if (err) { - ret.error = 'LOGIN_ERROR'; - srcWindow.postMessage(JSON.stringify(ret), domain); - return; - } - loadProxy(LocalStore.getUserHash()); - srcWindow.postMessage(JSON.stringify(ret), domain); - }); - return; - } else if (data.cmd === 'SIGN') { - if (!AUTHORIZED_DOMAINS.filter(function (x) { return x.test(domain); }).length) { - ret.error = "UNAUTH_DOMAIN"; - } else if (!LocalStore.isLoggedIn()) { - ret.error = "NOT_LOGGED_IN"; - } else { - return void whenReady(function () { - var sig = signMsg(data.data, proxy.edPrivate); - ret.res = { - uname: proxy.login_name, - edPublic: proxy.edPublic, - sig: sig - }; - ret.contacts = contacts; - srcWindow.postMessage(JSON.stringify(ret), domain); - }); - } - } else if (data.cmd === 'UPDATE_LIMIT') { - return void whenReady(function () { - if (rpcError) { - // Tell the user on accounts that there was an issue and they need to wait maximum 24h or contact an admin - ret.warning = true; - srcWindow.postMessage(JSON.stringify(ret), domain); - return; - } - rpc.updatePinLimits(function (e, limit, plan, note) { - if (e) { - ret.warning = true; - } - ret.res = [limit, plan, note]; - srcWindow.postMessage(JSON.stringify(ret), domain); - }); - }); - } else { - ret.error = "UNKNOWN_CMD"; - } - srcWindow.postMessage(JSON.stringify(ret), domain); - }); - - var userHash = LocalStore.getUserHash(); - if (userHash) { - loadProxy(userHash); - } -}); diff --git a/www/common/common-constants.js b/www/common/common-constants.js index 553665574..17db2302c 100644 --- a/www/common/common-constants.js +++ b/www/common/common-constants.js @@ -5,10 +5,6 @@ define(['/customize/application_config.js'], function (AppConfig) { userNameKey: 'User_name', blockHashKey: 'Block_hash', fileHashKey: 'FS_hash', - // sessionStorage - newPadPathKey: "newPadPath", - newPadTeamKey: "newPadTeam", - newPadFileData: "newPadFileData", // Store displayNameKey: 'cryptpad.username', oldStorageKey: 'CryptPad_RECENTPADS', diff --git a/www/common/onlyoffice/main.js b/www/common/onlyoffice/main.js index 83d887548..0560b95bd 100644 --- a/www/common/onlyoffice/main.js +++ b/www/common/onlyoffice/main.js @@ -55,7 +55,7 @@ define([ var addData = function (obj) { obj.ooType = window.location.pathname.replace(/^\//, '').replace(/\/$/, ''); obj.ooVersionHash = version; - obj.ooForceVersion = localStorage.CryptPad_ooVersion || sessionStorage.CryptPad_ooVersion || ""; + obj.ooForceVersion = localStorage.CryptPad_ooVersion || ""; }; var addRpc = function (sframeChan, Cryptpad, Utils) { sframeChan.on('Q_OO_SAVE', function (data, cb) { diff --git a/www/common/outer/async-store.js b/www/common/outer/async-store.js index 653c4d1f5..62e078050 100644 --- a/www/common/outer/async-store.js +++ b/www/common/outer/async-store.js @@ -2730,7 +2730,6 @@ define([ * - userHash or anonHash * Todo in cb * - LocalStore.setFSHash if needed - * - sessionStorage.User_Hash * - stuff with tokenKey * Event to outer * - requestLogin diff --git a/www/common/outer/local-store.js b/www/common/outer/local-store.js index 774924148..d15c2e8c6 100644 --- a/www/common/outer/local-store.js +++ b/www/common/outer/local-store.js @@ -82,19 +82,6 @@ define([ localStorage.setItem(Constants.userNameKey, name); if (cb) { cb(); } }; - var eraseTempSessionValues = LocalStore.eraseTempSessionValues = function () { - // delete sessionStorage values that might have been left over - // from the main page's /user redirect - [ - 'login', - 'login_user', - 'login_pass', - 'login_rmb', - 'register' - ].forEach(function (k) { - delete sessionStorage[k]; - }); - }; var logoutHandlers = []; LocalStore.logout = function (cb, isDeletion) { [ @@ -104,10 +91,8 @@ define([ 'loginToken', 'plan', ].forEach(function (k) { - sessionStorage.removeItem(k); localStorage.removeItem(k); delete localStorage[k]; - delete sessionStorage[k]; }); try { Object.keys(localStorage || {}).forEach(function (k) { @@ -122,7 +107,6 @@ define([ if (!LocalStore.getFSHash()) { LocalStore.setFSHash(Hash.createRandomHash('drive')); } - eraseTempSessionValues(); if (!isDeletion) { logoutHandlers.forEach(function (h) { diff --git a/www/common/sframe-channel.js b/www/common/sframe-channel.js deleted file mode 100644 index a7edf0814..000000000 --- a/www/common/sframe-channel.js +++ /dev/null @@ -1,166 +0,0 @@ -// This file provides the API for the channel for talking to and from the sandbox iframe. -define([ - '/common/sframe-protocol.js', - '/common/common-util.js' -], function (SFrameProtocol, Util) { - - var mkTxid = function () { - return Math.random().toString(16).replace('0.', '') + Math.random().toString(16).replace('0.', ''); - }; - - var create = function (ow, cb, isSandbox, sendData) { - var otherWindow; - var evReady = Util.mkEvent(true); - var handlers = {}; - var queries = {}; - - // list of handlers which are registered from the other side... - var insideHandlers = []; - var callWhenRegistered = {}; - - var chan = {}; - - // Send a query. channel.query('Q_SOMETHING', { args: "whatever" }, function (reply) { ... }); - chan.query = function (q, content, cb, opts) { - if (!otherWindow) { throw new Error('not yet initialized'); } - if (!SFrameProtocol[q]) { - throw new Error('please only make queries are defined in sframe-protocol.js'); - } - opts = opts || {}; - var txid = mkTxid(); - var to = opts.timeout || 30000; - var timeout = setTimeout(function () { - delete queries[txid]; - console.log("Timeout making query " + q); - }, to); - queries[txid] = function (data, msg) { - clearTimeout(timeout); - delete queries[txid]; - cb(undefined, data.content, msg); - }; - evReady.reg(function () { - otherWindow.postMessage(JSON.stringify({ - txid: txid, - content: content, - q: q - }), '*'); - }); - }; - - // Fire an event. channel.event('EV_SOMETHING', { args: "whatever" }); - var event = chan.event = function (e, content) { - if (!SFrameProtocol[e]) { - throw new Error('please only fire events that are defined in sframe-protocol.js'); - } - if (e.indexOf('EV_') !== 0) { - throw new Error('please only use events (starting with EV_) for event messages'); - } - evReady.reg(function () { - otherWindow.postMessage(JSON.stringify({ content: content, q: e }), '*'); - }); - }; - - // Be notified on query or event. channel.on('EV_SOMETHING', function (args, reply) { ... }); - // If the type is a query, your handler will be invoked with a reply function that takes - // one argument (the content to reply with). - chan.on = function (queryType, handler, quiet) { - if (!SFrameProtocol[queryType]) { - throw new Error('please only register handlers which are defined in sframe-protocol.js'); - } - (handlers[queryType] = handlers[queryType] || []).push(function (data, msg) { - handler(data.content, function (replyContent) { - if (queryType.indexOf('Q_') !== 0) { throw new Error("replies to events are invalid"); } - msg.source.postMessage(JSON.stringify({ - txid: data.txid, - content: replyContent - }), '*'); - }, msg); - }); - if (!quiet) { - event('EV_REGISTER_HANDLER', queryType); - } - }; - - // If a particular handler is registered, call the callback immediately, otherwise it will be called - // when that handler is first registered. - // channel.whenReg('Q_SOMETHING', function () { ...query Q_SOMETHING?... }); - chan.whenReg = function (queryType, cb, always) { - if (!SFrameProtocol[queryType]) { - throw new Error('please only register handlers which are defined in sframe-protocol.js'); - } - var reg = always; - if (insideHandlers.indexOf(queryType) > -1) { - cb(); - } else { - reg = true; - } - if (reg) { - (callWhenRegistered[queryType] = callWhenRegistered[queryType] || []).push(cb); - } - }; - - // Same as whenReg except it will invoke every time there is another registration, not just once. - chan.onReg = function (queryType, cb) { chan.whenReg(queryType, cb, true); }; - - chan.on('EV_REGISTER_HANDLER', function (content) { - if (callWhenRegistered[content]) { - callWhenRegistered[content].forEach(function (f) { f(); }); - delete callWhenRegistered[content]; - } - insideHandlers.push(content); - }); - chan.whenReg('EV_REGISTER_HANDLER', evReady.fire); - - // Make sure both iframes are ready - var isReady =false; - chan.onReady = function (h) { - if (isReady) { - return void h(); - } - if (typeof(h) !== "function") { return; } - chan.on('EV_RPC_READY', function () { isReady = true; h(); }); - }; - chan.ready = function () { - chan.whenReg('EV_RPC_READY', function () { - chan.event('EV_RPC_READY'); - }); - }; - - var txid; - window.addEventListener('message', function (msg) { - var data = JSON.parse(msg.data); - if (ow !== msg.source) { - return; - //console.log("DROP Message from unexpected source"); - //console.log(msg); - } else if (!otherWindow) { - otherWindow = ow; - sendData = sendData || {}; - sendData.txid = data.txid; - ow.postMessage(JSON.stringify(sendData), '*'); - cb(chan); - } else if (typeof(data.q) === 'string' && handlers[data.q]) { - handlers[data.q].forEach(function (f) { - f(data || JSON.parse(msg.data), msg); - data = undefined; - }); - } else if (typeof(data.q) === 'undefined' && queries[data.txid]) { - queries[data.txid](data, msg); - } else if (data.txid === txid) { - // stray message from init - return; - } else { - console.log("DROP Unhandled message"); - console.log(msg); - } - }); - if (isSandbox) { - // we're in the sandbox - otherWindow = ow; - evReady.fire(); - cb(chan); - } - }; - - return { create: create }; -}); diff --git a/www/common/sframe-common-outer.js b/www/common/sframe-common-outer.js index d476d02d4..f1fd0ac8d 100644 --- a/www/common/sframe-common-outer.js +++ b/www/common/sframe-common-outer.js @@ -1181,15 +1181,6 @@ define([ }); }); - sframeChan.on('Q_SESSIONSTORAGE_PUT', function (data, cb) { - if (typeof (data.value) === "undefined") { - delete sessionStorage[data.key]; - } else { - sessionStorage[data.key] = data.value; - } - cb(); - }); - sframeChan.on('Q_IS_ONLY_IN_SHARED_FOLDER', function (data, cb) { Cryptpad.isOnlyInSharedFolder(secret.channel, function (err, t) { if (err) { return void cb({error: err}); } diff --git a/www/common/sframe-common.js b/www/common/sframe-common.js index ffff122b5..3eb86ff93 100644 --- a/www/common/sframe-common.js +++ b/www/common/sframe-common.js @@ -462,15 +462,6 @@ define([ }); }; - funcs.sessionStorage = { - put: function (key, value, cb) { - ctx.sframeChan.query('Q_SESSIONSTORAGE_PUT', { - key: key, - value: value - }, cb); - } - }; - funcs.setDisplayName = function (name, cb) { cb = cb || $.noop; ctx.sframeChan.query('Q_SETTINGS_SET_DISPLAY_NAME', name, cb); diff --git a/www/common/sframe-protocol.js b/www/common/sframe-protocol.js deleted file mode 100644 index 5eb9d829e..000000000 --- a/www/common/sframe-protocol.js +++ /dev/null @@ -1,271 +0,0 @@ -// This file defines all of the RPC calls which are used between the inner and outer iframe. -// Define *querys* (which expect a response) using Q_ -// Define *events* (which expect no response) using EV_ -// Please document the queries and events you create, and please please avoid making generic -// "do stuff" events/queries which are used for many different things because it makes the -// protocol unclear. -// -// WARNING: At this point, this protocol is still EXPERIMENTAL. This is not it's final form. -// We need to define protocol one piece at a time and then when we are satisfied that we -// fully understand the problem, we will define the *right* protocol and this file will be dynomited. -// -define({ - // When the iframe first launches, this query is sent repeatedly by the controller - // to wait for it to awake and give it the requirejs config to use. - 'Q_INIT': true, - - // When either the outside or inside registers a query handler, this is sent. - 'EV_REGISTER_HANDLER': true, - - // When an iframe is ready to receive messages - 'EV_RPC_READY': true, - - // Realtime events called from the outside. - // When someone joins the pad, argument is a string with their netflux id. - 'EV_RT_JOIN': true, - // When someone leaves the pad, argument is a string with their netflux id. - 'EV_RT_LEAVE': true, - // When you have been disconnected, no arguments. - 'EV_RT_DISCONNECT': true, - // When you have connected, argument is an object with myID: string, members: list, readOnly: boolean. - 'EV_RT_CONNECT': true, - // Called after the history is finished synchronizing, no arguments. - 'EV_RT_READY': true, - // Called when the server returns an error in a pad (EEXPIRED, EDELETED). - 'EV_RT_ERROR': true, - // Called from both outside and inside, argument is a (string) chainpad message. - 'Q_RT_MESSAGE': true, - - // Called from the outside, this informs the inside whenever the user's data has been changed. - // The argument is the object representing the content of the user profile minus the netfluxID - // which changes per-reconnect. - 'EV_METADATA_UPDATE': true, - - // Takes one argument only, the title to set for the CURRENT pad which the user is looking at. - // This changes the pad title in drive ONLY, the pad title needs to be changed inside of the - // iframe and synchronized with the other users. This will not trigger a EV_METADATA_UPDATE - // because the metadata contained in EV_METADATA_UPDATE does not contain the pad title. - // It also sets the page (tab) title to the selected title, unles it is overridden by - // the EV_SET_TAB_TITLE event. - 'Q_SET_PAD_TITLE_IN_DRIVE': true, - // Set the page title (tab title) to the selected value which will override the pad title. - // The new title value can contain {title}, which will be replaced by the pad title when it - // is set or modified. - 'EV_SET_TAB_TITLE': true, - - // Update the user's display-name which will be shown to contacts and people in the same pads. - 'Q_SETTINGS_SET_DISPLAY_NAME': true, - - // Log the user out in all the tabs - 'Q_LOGOUT': true, - // Tell the user that he has been logged out from outside (probably from another tab) - 'EV_LOGOUT': true, - - // When moving to the login or register page from a pad, we need to redirect to that pad at the - // end of the login process. This query set the current href to the sessionStorage. - 'Q_SET_LOGIN_REDIRECT': true, - - // Store the editing or readonly link of the current pad to the clipboard (share button). - 'Q_STORE_LINK_TO_CLIPBOARD': true, - - // Use anonymous rpc from inside the iframe (for avatars & pin usage). - 'Q_ANON_RPC_MESSAGE': true, - - // Get the user's pin limit, usage and plan - 'Q_PIN_GET_USAGE': true, - - // Write/update the login block when the account password is changed - 'Q_WRITE_LOGIN_BLOCK': true, - - // Remove login blocks - 'Q_REMOVE_LOGIN_BLOCK': true, - - // Check the pin limit to determine if we can store the pad in the drive or if we should. - // display a warning - 'Q_GET_PIN_LIMIT_STATUS': true, - - // Move a pad to the trash when using the forget button. - 'Q_MOVE_TO_TRASH': true, - - // Request the full history from the server when the users clicks on the history button. - // Callback is called when the FULL_HISTORY_END message is received in the outside. - 'Q_GET_FULL_HISTORY': true, - 'Q_GET_HISTORY_RANGE': true, - // When a (full) history message is received from the server. - 'EV_RT_HIST_MESSAGE': true, - - // Save a pad as a template using the toolbar button - 'Q_SAVE_AS_TEMPLATE': true, - - // Friend requests from the userlist - 'Q_SEND_FRIEND_REQUEST': true, // Up query - 'Q_INCOMING_FRIEND_REQUEST': true, // Down query - 'EV_FRIEND_REQUEST': true, // Down event when the request is complete - - // Set the tab notification when the content of the pad changes - 'EV_NOTIFY': true, - - // Send the new settings to the inner iframe when they are changed in the proxy - 'EV_SETTINGS_UPDATE': true, - - // Get and set (pad) attributes stored in the drive from the inner iframe - 'Q_GET_ATTRIBUTE': true, - 'Q_SET_ATTRIBUTE': true, - 'Q_GET_PAD_ATTRIBUTE': true, - 'Q_SET_PAD_ATTRIBUTE': true, - - // Check if a pad is only in a shared folder or (also) in the main drive. - // This allows us to change the behavior of some buttons (trash icon...) - 'Q_IS_ONLY_IN_SHARED_FOLDER': true, - - // Open/close the File picker (sent from the iframe to the outside) - 'EV_FILE_PICKER_OPEN': true, - 'EV_FILE_PICKER_CLOSE': true, - 'EV_FILE_PICKER_REFRESH': true, - // File selected in the file picker: sent from the filepicker iframe to the outside - // and then send to the inner iframe - 'EV_FILE_PICKED': true, - - // Get all the files from the drive to display them in a file picker secure app - 'Q_GET_FILES_LIST': true, - - // Template picked, replace the content of the pad - 'Q_TEMPLATE_USE': true, - // Check if we have template(s) for the selected pad type - 'Q_TEMPLATE_EXIST': true, - - // File upload queries and events - 'Q_UPLOAD_FILE': true, - 'EV_FILE_UPLOAD_STATE': true, - 'Q_CANCEL_PENDING_FILE_UPLOAD': true, - - // Make the browser window navigate to a given URL, if no URL is passed then it will reload. - 'EV_GOTO_URL': true, - // Make the parent window open a given URL in a new tab. It allows us to keep sessionStorage - // form the parent window. - 'EV_OPEN_URL': true, - - // Present mode URL - 'Q_PRESENT_URL_GET_VALUE': true, - 'EV_PRESENT_URL_SET_VALUE': true, - - // Put one or more entries to the cache which will go in localStorage. - // Cache is wiped after each new release - 'EV_CACHE_PUT': true, - - // Chat - 'EV_CHAT_EVENT': true, - 'Q_CHAT_COMMAND': true, - 'Q_CHAT_OPENPADCHAT': true, - - // Cursor - 'EV_CURSOR_EVENT': true, - 'Q_CURSOR_COMMAND': true, - 'Q_CURSOR_OPENCHANNEL': true, - - // Put one or more entries to the localStore which will go in localStorage. - 'EV_LOCALSTORE_PUT': true, - // Put one entry in the parent sessionStorage - 'Q_SESSIONSTORAGE_PUT': true, - - // Merge the anonymous drive (FS_hash) into the current logged in user's drive, to keep the pads - // in the drive at registration. - 'Q_MERGE_ANON_DRIVE': true, - - // 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, - - // Store outside and get thumbnails inside (stored with localForage (indexedDB) outside) - 'Q_THUMBNAIL_SET': true, - 'Q_THUMBNAIL_GET': true, - - // Settings app only - // Clear all thumbnails - 'Q_THUMBNAIL_CLEAR': true, - // Backup and restore a drive - 'Q_SETTINGS_DRIVE_GET': true, - 'Q_SETTINGS_DRIVE_SET': true, - 'Q_SETTINGS_DRIVE_RESET': true, - // Logout from all the devices where the account is logged in - 'Q_SETTINGS_LOGOUT': true, - // Import pads from this computer's anon session into the current user account - 'Q_SETTINGS_IMPORT_LOCAL': true, - 'Q_SETTINGS_DELETE_ACCOUNT': true, - - // Store the language selected in the iframe into localStorage outside - 'Q_LANGUAGE_SET': true, - - // Anonymous users can empty their drive and remove FS_hash from localStorage - 'EV_BURN_ANON_DRIVE': true, - // Inner drive needs to send command and receive updates from the async store - 'Q_DRIVE_USEROBJECT': true, - 'Q_DRIVE_GETOBJECT': true, - 'Q_DRIVE_RESTORE': true, - // Get the pads deleted from the server by other users to remove them from the drive - 'Q_DRIVE_GETDELETED': true, - // Store's userObject need to send log messages to inner to display them in the UI - 'EV_DRIVE_LOG': true, - // Refresh the drive when the drive has changed ('change' or 'remove' events) - 'EV_DRIVE_CHANGE': true, - 'EV_DRIVE_REMOVE': true, - // Set shared folder hash in the address bar - 'EV_DRIVE_SET_HASH': true, - - // Remove an owned pad from the server - 'Q_REMOVE_OWNED_CHANNEL': true, - // Clear an owned pad from the server (preserve metadata) - 'Q_CLEAR_OWNED_CHANNEL': true, - - // Notifications about connection and disconnection from the network - 'EV_NETWORK_DISCONNECT': true, - 'EV_NETWORK_RECONNECT': true, - // Reload on new version - 'EV_NEW_VERSION': true, - - // Pad creation screen: create a pad with the selected attributes (owned, expire) - 'Q_CREATE_PAD': true, - // Get the available templates - 'Q_CREATE_TEMPLATES': true, - - // This is for sending data out of the iframe when we are in testing mode - // The exact protocol is defined in common/test.js - 'EV_TESTDATA': true, - - // OnlyOffice: save a new version - 'Q_OO_SAVE': true, - - // Ask for the pad password when a pad is protected - 'EV_PAD_PASSWORD': true, - 'Q_PAD_PASSWORD_VALUE': true, - // Change pad password - 'Q_PAD_PASSWORD_CHANGE': true, - - // Migrate drive to owned drive - 'Q_CHANGE_USER_PASSWORD': true, - - // Loading events to display in the loading screen - 'EV_LOADING_INFO': true, - // Critical error outside the iframe during loading screen - 'EV_LOADING_ERROR': true, - - // Chrome 68 bug... - 'EV_CHROME_68': true, - - // Get all existing tags - 'Q_GET_ALL_TAGS': true, - - // Store pads in the drive - 'EV_AUTOSTORE_DISPLAY_POPUP': true, - 'Q_AUTOSTORE_STORE': true, - 'Q_IS_PAD_STORED': true, - - // Import mediatag from a pad - 'Q_IMPORT_MEDIATAG': true, - - // Ability to get a pad's content from its hash - 'Q_CRYPTGET': true, - 'EV_CRYPTGET_DISCONNECT': true, - -}); diff --git a/www/login/main.js b/www/login/main.js index 40a82b27e..768c012a8 100644 --- a/www/login/main.js +++ b/www/login/main.js @@ -67,10 +67,8 @@ define([ }); }); $('#register').on('click', function () { - if (sessionStorage) { - if ($uname.val()) { - sessionStorage.login_user = $uname.val(); - } + if ($uname.val()) { + localStorage.login_user = $uname.val(); } window.location.href = '/register/'; }); diff --git a/www/logout/main.js b/www/logout/main.js index acd8e8b02..d23bb8969 100644 --- a/www/logout/main.js +++ b/www/logout/main.js @@ -1,5 +1,4 @@ define(['/bower_components/localforage/dist/localforage.min.js'], function (localForage) { localForage.clear(); - sessionStorage.clear(); localStorage.clear(); }); diff --git a/www/register/main.js b/www/register/main.js index e2c30ea64..39069bd94 100644 --- a/www/register/main.js +++ b/www/register/main.js @@ -37,9 +37,9 @@ define([ var $passwd = $('#password'); var $confirm = $('#password-confirm'); - if (sessionStorage.login_user) { - delete sessionStorage.login_user; - $uname.val(sessionStorage.login_user); + if (localStorage.login_user) { + $uname.val(localStorage.login_user); + delete loginStorage.login_user; } [ $uname, $passwd, $confirm]