From 521b59088b7ce7e2af89b29326daf6a0617d3b41 Mon Sep 17 00:00:00 2001 From: ansuz Date: Thu, 18 Jun 2020 15:24:58 -0400 Subject: [PATCH 01/27] fix unreadable team chat input text color --- www/teams/app-team.less | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/teams/app-team.less b/www/teams/app-team.less index c59d0dcb9..abd46d121 100644 --- a/www/teams/app-team.less +++ b/www/teams/app-team.less @@ -45,7 +45,7 @@ .cp-app-contacts-input { textarea { border: 0px; - color: white; + color: @cryptpad_text_col; } } } From 434ba6c360208b91d848561e311fc66543a38f2e Mon Sep 17 00:00:00 2001 From: "Francisco J. Solis-Munoz" Date: Tue, 22 Sep 2020 09:43:36 -0500 Subject: [PATCH 02/27] Fixed content security policy for local development to same IP as server.js --- config/config.example.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/config.example.js b/config/config.example.js index 3826a7291..fabddce26 100644 --- a/config/config.example.js +++ b/config/config.example.js @@ -46,7 +46,7 @@ module.exports = { * cryptpad/docs/example.nginx.conf (see the $main_domain variable) * */ - httpUnsafeOrigin: 'http://localhost:3000/', + httpUnsafeOrigin: 'http://127.0.0.1:3000/', /* httpSafeOrigin is the URL that is used for the 'sandbox' described above. * If you're testing or developing with CryptPad on your local machine then From 05cbe20bbe59a4bf4aa48ff2d70a42597a465cd3 Mon Sep 17 00:00:00 2001 From: "Francisco J. Solis-Munoz" Date: Tue, 22 Sep 2020 09:51:26 -0500 Subject: [PATCH 03/27] Unsafe origin for localhost as 127.0.0.1 --- config/config.example.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/config.example.js b/config/config.example.js index fabddce26..3f0437953 100644 --- a/config/config.example.js +++ b/config/config.example.js @@ -46,7 +46,7 @@ module.exports = { * cryptpad/docs/example.nginx.conf (see the $main_domain variable) * */ - httpUnsafeOrigin: 'http://127.0.0.1:3000/', + httpUnsafeOrigin: 'http://127.0.0.1:3000/ http://localhost:3000', /* httpSafeOrigin is the URL that is used for the 'sandbox' described above. * If you're testing or developing with CryptPad on your local machine then From 36bed265d51ec61b5f58ff6e470ee1d9ec2e0ff2 Mon Sep 17 00:00:00 2001 From: ansuz Date: Wed, 24 Feb 2021 13:44:55 +0530 Subject: [PATCH 04/27] reenable surveyURL in dropdown menu --- www/common/common-ui-elements.js | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index 50c4b34ee..361265df5 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -1709,21 +1709,7 @@ define([ }, }); } -/* - if (AppConfig.surveyURL) { - options.push({ - tag: 'a', - attributes: { - 'class': 'cp-toolbar-survey fa fa-graduation-cap' - }, - content: h('span', Messages.survey), - action: function () { - Common.openUnsafeURL(AppConfig.surveyURL); - Feedback.send('SURVEY_CLICKED'); - }, - }); - } -*/ + options.push({ tag: 'a', attributes: { @@ -1780,6 +1766,20 @@ define([ }); } + if (AppConfig.surveyURL) { + options.push({ + tag: 'a', + attributes: { + 'class': 'cp-toolbar-survey fa fa-graduation-cap' + }, + content: h('span', Messages.survey), + action: function () { + Common.openUnsafeURL(AppConfig.surveyURL); + Feedback.send('SURVEY_CLICKED'); + }, + }); + } + options.push({ tag: 'hr' }); // Add login or logout button depending on the current status if (priv.loggedIn) { From 2d938f971ececa14f755f0e1f7f70c24192f912a Mon Sep 17 00:00:00 2001 From: ansuz Date: Tue, 2 Mar 2021 12:15:46 +0530 Subject: [PATCH 05/27] prototype a replacement for the current help menu --- www/common/common-ui-elements.js | 37 ++++++++++++++++---------------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index 8b5101fb7..b2e9229a9 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -1092,29 +1092,30 @@ define([ return e; }; - UIElements.createHelpMenu = function (common, categories) { + UIElements.createHelpMenu = function (common /*, categories */) { var type = common.getMetadataMgr().getMetadata().type || 'pad'; - var elements = []; - if (Messages.help && Messages.help.generic) { - Object.keys(Messages.help.generic).forEach(function (el) { - elements.push(setHTML(h('li'), Messages.help.generic[el])); - }); - } - if (categories) { - categories.forEach(function (cat) { - var msgs = Messages.help[cat]; - if (msgs) { - Object.keys(msgs).forEach(function (el) { - elements.push(setHTML(h('li'), msgs[el])); - }); - } - }); + + var apps = { + pad: 'richtext', + code: 'code', + slide: 'slides', + sheet: 'sheets', + poll: 'poll', + kanban: 'kanban', + whiteboard: 'whiteboard', + }; + + var href = "https://docs.cryptpad.fr/en/user_guide/applications.html"; + if (apps[type]) { + href = "https://docs.cryptpad.fr/en/user_guide/apps/" + apps[type] + ".html"; } + var content = setHTML(h('p'), Messages.help.generic.more); + $(content).find('a').attr('href', href); + var text = h('p.cp-help-text', [ - h('h1', Messages.help.title), - h('ul', elements) + content ]); common.fixLinks(text); From d43cb509dc3e687a55f7e3f9f40d9bf49840eb00 Mon Sep 17 00:00:00 2001 From: yflory Date: Tue, 2 Mar 2021 16:05:18 +0100 Subject: [PATCH 06/27] Checkup: test sandbox domain and login block --- customize.dist/login.js | 5 +- .../src/less2/pages/page-checkup.less | 4 + www/checkup/index.html | 1 + www/checkup/inner.html | 11 ++ www/checkup/inner.js | 5 + www/checkup/main.js | 122 +++++++++++++++++- 6 files changed, 141 insertions(+), 7 deletions(-) create mode 100644 www/checkup/inner.html create mode 100644 www/checkup/inner.js diff --git a/customize.dist/login.js b/customize.dist/login.js index 0e932c4f6..c0daaec91 100644 --- a/customize.dist/login.js +++ b/customize.dist/login.js @@ -22,6 +22,7 @@ define([ Feedback, LocalStore, Messages, nThen, Block, Hash) { var Exports = { Cred: Cred, + Block: Block, // this is depended on by non-customizable files // be careful when modifying login.js requiredBytes: 192, @@ -92,7 +93,7 @@ define([ }; - var loginOptionsFromBlock = function (blockInfo) { + var loginOptionsFromBlock = Exports.loginOptionsFromBlock = function (blockInfo) { var opt = {}; var parsed = Hash.getSecrets('pad', blockInfo.User_hash); opt.channelHex = parsed.channel; @@ -102,7 +103,7 @@ define([ return opt; }; - var loadUserObject = function (opt, cb) { + var loadUserObject = Exports.loadUserObject = function (opt, cb) { var config = { websocketURL: NetConfig.getWebsocketURL(), channel: opt.channelHex, diff --git a/customize.dist/src/less2/pages/page-checkup.less b/customize.dist/src/less2/pages/page-checkup.less index a4ece61a4..2839ec9ea 100644 --- a/customize.dist/src/less2/pages/page-checkup.less +++ b/customize.dist/src/less2/pages/page-checkup.less @@ -53,5 +53,9 @@ html, body { background-color: @cp_alerts-danger-bg; color: @cp_alerts-danger-text; } + + iframe { + display: none; + } } diff --git a/www/checkup/index.html b/www/checkup/index.html index afa469f7f..164793466 100644 --- a/www/checkup/index.html +++ b/www/checkup/index.html @@ -6,4 +6,5 @@ + diff --git a/www/checkup/inner.html b/www/checkup/inner.html new file mode 100644 index 000000000..4554943d5 --- /dev/null +++ b/www/checkup/inner.html @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/www/checkup/inner.js b/www/checkup/inner.js new file mode 100644 index 000000000..690bfde24 --- /dev/null +++ b/www/checkup/inner.js @@ -0,0 +1,5 @@ +define([ + 'jquery', +], function ($) { + console.log('inner loaded'); +}); diff --git a/www/checkup/main.js b/www/checkup/main.js index 171699a22..3caed1a84 100644 --- a/www/checkup/main.js +++ b/www/checkup/main.js @@ -4,12 +4,19 @@ define([ '/assert/assertions.js', '/common/hyperscript.js', '/customize/messages.js', + '/common/dom-ready.js', + '/bower_components/nthen/index.js', '/common/sframe-common-outer.js', + '/customize/login.js', + '/common/common-hash.js', + '/common/common-util.js', + '/common/pinpad.js', '/bower_components/tweetnacl/nacl-fast.min.js', 'less!/customize/src/less2/pages/page-checkup.less', -], function ($, ApiConfig, Assertions, h, Messages /*, SFCommonO*/) { +], function ($, ApiConfig, Assertions, h, Messages, DomReady, + nThen, SFCommonO, Login, Hash, Util, Pinpad) { var assert = Assertions(); var trimSlashes = function (s) { @@ -41,7 +48,7 @@ define([ var checkAvailability = function (url, cb) { $.ajax({ url: url, - date: {}, + data: {}, complete: function (xhr) { cb(xhr.status === 200); }, @@ -52,10 +59,115 @@ define([ checkAvailability(trimmedUnsafe, cb); }, _alert("Main domain is not available")); + // Try loading an iframe on the safe domain assert(function (cb) { - console.log(trimmedSafe); - checkAvailability(trimmedSafe, cb); - }, _alert("Sandbox domain is not available")); // FIXME Blocked by CSP. try loading it via sframe ? + var to; + nThen(function (waitFor) { + DomReady.onReady(waitFor()); + }).nThen(function (waitFor) { + to = setTimeout(function () { + console.error('TIMEOUT loading iframe on the safe domain') + cb(false); + }, 5000); + SFCommonO.initIframe(waitFor); + }).nThen(function () { + // Iframe is loaded + clearTimeout(to); + cb(true); + }); + }, _alert("Sandbox domain is not available")); + + // Write/ready access to /block/ + assert(function (cb) { + var bytes = new Uint8Array(Login.requiredBytes); + + var opt = Login.allocateBytes(bytes); + + var blockUrl = Login.Block.getBlockUrl(opt.blockKeys); + var blockRequest = Login.Block.serialize("{}", opt.blockKeys); + var removeRequest = Login.Block.remove(opt.blockKeys); + console.log('Test block URL:', blockUrl); + + var userHash = '/2/drive/edit/000000000000000000000000'; + var secret = Hash.getSecrets('drive', userHash); + opt.keys = secret.keys; + opt.channelHex = secret.channel; + + var RT, rpc, exists; + + nThen(function (waitFor) { + Util.fetch(blockUrl, waitFor(function (err, block) { + if (err) { return; } // No block found + exists = true; + })); + }).nThen(function (waitFor) { + // Create proxy + Login.loadUserObject(opt, waitFor(function (err, rt) { + if (err) { + waitFor.abort(); + console.error("Can't create new channel. This may also be a websocket issue."); + return void cb(false); + } + RT = rt; + var proxy = rt.proxy; + proxy.edPublic = opt.edPublic; + proxy.edPrivate = opt.edPrivate; + proxy.curvePublic = opt.curvePublic; + proxy.curvePrivate = opt.curvePrivate; + rt.realtime.onSettle(waitFor()); + })); + }).nThen(function (waitFor) { + // Init RPC + Pinpad.create(RT.network, RT.proxy, waitFor(function (e, _rpc) { + if (e) { + waitFor.abort(); + console.error("Can't initialize RPC", e); // INVALID_KEYS + return void cb(false); + } + rpc = _rpc; + })); + }).nThen(function (waitFor) { + // Write block + if (exists) { return; } + rpc.writeLoginBlock(blockRequest, waitFor(function (e) { + if (e) { + waitFor.abort(); + console.error("Can't write login block", e); + return void cb(false); + } + })); + }).nThen(function (waitFor) { + // Read block + Util.fetch(blockUrl, waitFor(function (e, block) { + if (e) { + waitFor.abort(); + console.error("Can't read login block", e); + return void cb(false); + } + })); + }).nThen(function (waitFor) { + // Remove block + rpc.removeLoginBlock(removeRequest, waitFor(function (e) { + if (e) { + waitFor.abort(); + console.error("Can't remove login block", e); + console.error(blockRequest); + return void cb(false); + } + })); + }).nThen(function (waitFor) { + rpc.removeOwnedChannel(secret.channel, waitFor(function (e) { + if (e) { + waitFor.abort(); + console.error("Can't remove channel", e); + return void cb(false); + } + })); + }).nThen(function () { + cb(true); + }); + + }, _alert("Login Block is not working (write/read/remove)")); var row = function (cells) { return h('tr', cells.map(function (cell) { From b0e0a8dc75385015788422c76a23594ebfe96c0e Mon Sep 17 00:00:00 2001 From: yflory Date: Tue, 2 Mar 2021 16:45:52 +0100 Subject: [PATCH 07/27] Add spinner to the checkup page and test websockets --- .../src/less2/pages/page-checkup.less | 6 +++ www/assert/assertions.js | 5 +- www/checkup/index.html | 1 + www/checkup/main.js | 50 +++++++++++++++++-- 4 files changed, 57 insertions(+), 5 deletions(-) diff --git a/customize.dist/src/less2/pages/page-checkup.less b/customize.dist/src/less2/pages/page-checkup.less index 2839ec9ea..2a05600c7 100644 --- a/customize.dist/src/less2/pages/page-checkup.less +++ b/customize.dist/src/less2/pages/page-checkup.less @@ -20,6 +20,12 @@ html, body { padding-top: 15px; } + .pending { + border: 1px solid white; + .fa { + margin-right: 20px; + } + } .success { border: 1px solid green; } diff --git a/www/assert/assertions.js b/www/assert/assertions.js index 8ea0a2638..a1f6944fb 100644 --- a/www/assert/assertions.js +++ b/www/assert/assertions.js @@ -21,8 +21,10 @@ define([], function () { }); }; - assert.run = function (cb) { + assert.run = function (cb, progress) { + progress = progress || function () {}; var count = ASSERTS.length; + var total = ASSERTS.length; var done = function (err) { count--; if (err) { failMessages.push(err); } @@ -38,6 +40,7 @@ define([], function () { ASSERTS.forEach(function (f, index) { f(function (err) { //console.log("test " + index); + progress(index, total); done(err, index); }, index); }); diff --git a/www/checkup/index.html b/www/checkup/index.html index 164793466..04a9502d3 100644 --- a/www/checkup/index.html +++ b/www/checkup/index.html @@ -6,5 +6,6 @@ +
diff --git a/www/checkup/main.js b/www/checkup/main.js index 3caed1a84..5a6630c6f 100644 --- a/www/checkup/main.js +++ b/www/checkup/main.js @@ -11,12 +11,15 @@ define([ '/common/common-hash.js', '/common/common-util.js', '/common/pinpad.js', - + '/common/outer/network-config.js', + '/bower_components/netflux-websocket/netflux-client.js', '/bower_components/tweetnacl/nacl-fast.min.js', + 'css!/bower_components/components-font-awesome/css/font-awesome.min.css', 'less!/customize/src/less2/pages/page-checkup.less', ], function ($, ApiConfig, Assertions, h, Messages, DomReady, - nThen, SFCommonO, Login, Hash, Util, Pinpad) { + nThen, SFCommonO, Login, Hash, Util, Pinpad, + NetConfig, Netflux) { var assert = Assertions(); var trimSlashes = function (s) { @@ -77,7 +80,28 @@ define([ }); }, _alert("Sandbox domain is not available")); - // Write/ready access to /block/ + // Test Websocket + var evWSError = Util.mkEvent(true); + assert(function (cb) { + var ws = new WebSocket(NetConfig.getWebsocketURL()); + var to = setTimeout(function () { + console.error('Websocket TIMEOUT'); + evWSError.fire(); + cb('TIMEOUT (5 seconds)'); + }, 5000); + ws.onopen = function () { + clearTimeout(to); + cb(true); + }; + ws.onerror = function (err) { + clearTimeout(to); + console.error('Websocket error', err); + evWSError.fire(); + cb('WebSocket error: check your console'); + }; + }, _alert("Websocket is not available")); + + // Test login block assert(function (cb) { var bytes = new Uint8Array(Login.requiredBytes); @@ -101,6 +125,11 @@ define([ exists = true; })); }).nThen(function (waitFor) { + // If WebSockets aren't working, don't wait forever here + evWSError.reg(function () { + waitFor.abort(); + cb("No WebSocket (test number 6)"); + }); // Create proxy Login.loadUserObject(opt, waitFor(function (err, rt) { if (err) { @@ -167,7 +196,7 @@ define([ cb(true); }); - }, _alert("Login Block is not working (write/read/remove)")); + }, _alert("Login block is not working (write/read/remove)")); var row = function (cells) { return h('tr', cells.map(function (cell) { @@ -185,6 +214,8 @@ define([ ]); }; + var completed = 0; + var $progress = $('#cp-progress'); assert.run(function (state) { var errors = state.errors; var failed = errors.length; @@ -206,6 +237,17 @@ define([ h('div.failures', errors.map(failureReport)), ]); + $progress.remove(); $('body').prepend(report); + }, function (i, total) { + console.log('test '+ i +' completed'); + completed++; + Messages.assert_numberOfTestsCompleted = "{0} / {1} tests completed."; + $progress.html('').append(h('div.report.pending.summary', [ + h('p', [ + h('i.fa.fa-spinner.fa-pulse'), + h('span', Messages._getKey('assert_numberOfTestsCompleted', [completed, total])) + ]) + ])); }); }); From 40e9da566e2630f847d3c39b3df84e59d11f2c97 Mon Sep 17 00:00:00 2001 From: yflory Date: Tue, 2 Mar 2021 17:48:38 +0100 Subject: [PATCH 08/27] lint compliance --- www/checkup/inner.js | 3 +-- www/checkup/main.js | 9 ++++----- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/www/checkup/inner.js b/www/checkup/inner.js index 690bfde24..f752bc2ad 100644 --- a/www/checkup/inner.js +++ b/www/checkup/inner.js @@ -1,5 +1,4 @@ define([ - 'jquery', -], function ($) { +], function () { console.log('inner loaded'); }); diff --git a/www/checkup/main.js b/www/checkup/main.js index 5a6630c6f..06b69e12b 100644 --- a/www/checkup/main.js +++ b/www/checkup/main.js @@ -12,14 +12,13 @@ define([ '/common/common-util.js', '/common/pinpad.js', '/common/outer/network-config.js', - '/bower_components/netflux-websocket/netflux-client.js', '/bower_components/tweetnacl/nacl-fast.min.js', 'css!/bower_components/components-font-awesome/css/font-awesome.min.css', 'less!/customize/src/less2/pages/page-checkup.less', ], function ($, ApiConfig, Assertions, h, Messages, DomReady, nThen, SFCommonO, Login, Hash, Util, Pinpad, - NetConfig, Netflux) { + NetConfig) { var assert = Assertions(); var trimSlashes = function (s) { @@ -69,7 +68,7 @@ define([ DomReady.onReady(waitFor()); }).nThen(function (waitFor) { to = setTimeout(function () { - console.error('TIMEOUT loading iframe on the safe domain') + console.error('TIMEOUT loading iframe on the safe domain'); cb(false); }, 5000); SFCommonO.initIframe(waitFor); @@ -120,7 +119,7 @@ define([ var RT, rpc, exists; nThen(function (waitFor) { - Util.fetch(blockUrl, waitFor(function (err, block) { + Util.fetch(blockUrl, waitFor(function (err) { if (err) { return; } // No block found exists = true; })); @@ -167,7 +166,7 @@ define([ })); }).nThen(function (waitFor) { // Read block - Util.fetch(blockUrl, waitFor(function (e, block) { + Util.fetch(blockUrl, waitFor(function (e) { if (e) { waitFor.abort(); console.error("Can't read login block", e); From 8cc0f75f495b51b906960f516bcbc3cdac6c635c Mon Sep 17 00:00:00 2001 From: yflory Date: Tue, 2 Mar 2021 18:19:07 +0100 Subject: [PATCH 09/27] Fix user logged out after registration --- www/common/cryptpad-common.js | 2 +- www/common/outer/async-store.js | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/www/common/cryptpad-common.js b/www/common/cryptpad-common.js index e33c5f429..2084cb1e1 100644 --- a/www/common/cryptpad-common.js +++ b/www/common/cryptpad-common.js @@ -2271,6 +2271,7 @@ define([ var channelIsReady = waitFor(); + updateLocalVersion(); var msgEv = Util.mkEvent(); var postMsg, worker; @@ -2504,7 +2505,6 @@ define([ AppConfig.afterLogin(common, waitFor()); } }).nThen(function () { - updateLocalVersion(); f(void 0, env); if (typeof(window.onhashchange) === 'function') { window.onhashchange(); } }); diff --git a/www/common/outer/async-store.js b/www/common/outer/async-store.js index 63a7fc352..ccf179245 100644 --- a/www/common/outer/async-store.js +++ b/www/common/outer/async-store.js @@ -2687,7 +2687,8 @@ define([ // every user object should have a persistent, random number if (typeof(proxy.loginToken) !== 'number') { - proxy[Constants.tokenKey] = Math.floor(Math.random()*Number.MAX_SAFE_INTEGER); + proxy[Constants.tokenKey] = store.data.localToken || + Math.floor(Math.random()*Number.MAX_SAFE_INTEGER); } returned[Constants.tokenKey] = proxy[Constants.tokenKey]; @@ -2848,11 +2849,14 @@ define([ store.driveMetadata = info.metadata; if (!rt.proxy.drive || typeof(rt.proxy.drive) !== 'object') { rt.proxy.drive = {}; } var drive = rt.proxy.drive; + /* + // XXX deprecating localStorage migration // Creating a new anon drive: import anon pads from localStorage if ((!drive[Constants.oldStorageKey] || !Array.isArray(drive[Constants.oldStorageKey])) && !drive['filesData']) { drive[Constants.oldStorageKey] = []; } + */ // Drive already exist: return the existing drive, don't load data from legacy store if (store.manager) { // If a cache is loading, make sure it is complete before calling onReady From 88c9589c49bceb2404aa7ac9ad300748ec637373 Mon Sep 17 00:00:00 2001 From: yflory Date: Tue, 2 Mar 2021 18:22:00 +0100 Subject: [PATCH 10/27] lint compliance --- www/common/outer/async-store.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/common/outer/async-store.js b/www/common/outer/async-store.js index ccf179245..189ac9f56 100644 --- a/www/common/outer/async-store.js +++ b/www/common/outer/async-store.js @@ -2848,9 +2848,9 @@ define([ if (store.ready) { return; } // the store is already ready, it is a reconnection store.driveMetadata = info.metadata; if (!rt.proxy.drive || typeof(rt.proxy.drive) !== 'object') { rt.proxy.drive = {}; } - var drive = rt.proxy.drive; /* // XXX deprecating localStorage migration + var drive = rt.proxy.drive; // Creating a new anon drive: import anon pads from localStorage if ((!drive[Constants.oldStorageKey] || !Array.isArray(drive[Constants.oldStorageKey])) && !drive['filesData']) { From 3c4b2ffad0e45163f62742cae7ed50fd5c12b78f Mon Sep 17 00:00:00 2001 From: ansuz Date: Wed, 3 Mar 2021 09:59:04 +0530 Subject: [PATCH 11/27] avoid setting headers for /api/config that will be duplicated by nginx --- server.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/server.js b/server.js index 9e26500ad..33ffff10d 100644 --- a/server.js +++ b/server.js @@ -162,6 +162,8 @@ app.use(function (req, res, next) { return void res.end(); } + if (/^\/api\/config/.test(req.url)) { return void next(); } + setHeaders(req, res); if (/[\?\&]ver=[^\/]+$/.test(req.url)) { res.setHeader("Cache-Control", "max-age=31536000"); } else { res.setHeader("Cache-Control", "no-cache"); } From 1ef6a96cd1b15c3179f4f365eb25e73d89ecadd8 Mon Sep 17 00:00:00 2001 From: ansuz Date: Wed, 3 Mar 2021 11:11:06 +0530 Subject: [PATCH 12/27] avoid duplicating CSP headers in production environments --- server.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/server.js b/server.js index 33ffff10d..f3ee71d0b 100644 --- a/server.js +++ b/server.js @@ -107,6 +107,9 @@ var setHeaders = (function () { "Cross-Origin-Embedder-Policy": 'require-corp', }); + // Don't set CSP headers on /api/config because they aren't necessary and they cause problems + // when duplicated by NGINX in production environments + if (/^\/api\/config/.test(req.url)) { return; } // targeted CSP, generic policies, maybe custom headers const h = [ /^\/common\/onlyoffice\/.*\/index\.html.*/, @@ -162,8 +165,6 @@ app.use(function (req, res, next) { return void res.end(); } - if (/^\/api\/config/.test(req.url)) { return void next(); } - setHeaders(req, res); if (/[\?\&]ver=[^\/]+$/.test(req.url)) { res.setHeader("Cache-Control", "max-age=31536000"); } else { res.setHeader("Cache-Control", "no-cache"); } From 5a71042568c7b44595e3866f1be9c5e0254ffcd6 Mon Sep 17 00:00:00 2001 From: ansuz Date: Wed, 3 Mar 2021 17:00:28 +0530 Subject: [PATCH 13/27] remove XXX note --- www/common/outer/async-store.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/common/outer/async-store.js b/www/common/outer/async-store.js index 189ac9f56..0a58720ad 100644 --- a/www/common/outer/async-store.js +++ b/www/common/outer/async-store.js @@ -2849,7 +2849,7 @@ define([ store.driveMetadata = info.metadata; if (!rt.proxy.drive || typeof(rt.proxy.drive) !== 'object') { rt.proxy.drive = {}; } /* - // XXX deprecating localStorage migration + // deprecating localStorage migration as of 4.2.0 var drive = rt.proxy.drive; // Creating a new anon drive: import anon pads from localStorage if ((!drive[Constants.oldStorageKey] || !Array.isArray(drive[Constants.oldStorageKey])) From 022ecc39477785d8e92035570204d6fceea6e9f5 Mon Sep 17 00:00:00 2001 From: ansuz Date: Wed, 3 Mar 2021 17:36:55 +0530 Subject: [PATCH 14/27] update changelog with final notes --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c28772421..0863a368e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,6 +35,7 @@ To update from 4.1.0 to 4.2.0: * Server administrators can now refresh the _performance_ table on the admin panel without reloading the page. * We've begun working on a _checkup_ page for CryptPad to help administrators identify and fix common misconfigurations of the platform. It's still in a very basic state, but we hope to to make it a core part of the server installation guide that is under development. * The kanban app now supports import like the rest of our apps and rejects content of any file-type other than JSON. +* We've dropped support for a very old migration that handled user accounts that had not been accessed fo several years. This should make everyone else's account slightly faster. ## Bug fixes @@ -55,10 +56,12 @@ To update from 4.1.0 to 4.2.0: * The client will now check whether a file is larger than is allowed by the server before attempting to upload it, rather failing only when the server rejects the upload. * The drive no longer allows files to be dragged and dropped into locations other than the "Documents" section, as it did not make sense for files to be displayed anywhere else. * We identified and fixed a number of issues which caused shared folders that were protected with access lists to fail to load due to race conditions between loading the document and authenticating with the server as a user or member of a team. This could also result in a loss of access to documents stored exclusively in those shared folders. +* There was a similar race condition that could occur when registering an account that could cause some parts of the UI to get stuck offline. * We've fixed a number of server issues: 1. A change in a function signature in late December caused the upload of unowned files to fail to complete. 2. Messages sent via websocket are no longer broadcast to other members of a session until they have been validated by the server and stored on the disk. This was not a security issue as clients validate messages anyway, however, it could cause inconsistencies in documents when some members of a session incorrectly believed that a message had been saved. 3. A subtle race condition in very specific circumstances could cause the server's in-memory index for a given session to become incorrect. This could cause one or two messages to be omitted when requesting the most recent history. We observed this in practice when some clients did not realize they had been kicked from a team. This is unlikely to have affected anyone in practice because it only occurred when reconnecting using cached messages for the document which records team membership, and this functionality is only being introduced in this release. + 4. Several HTTP headers were set by both our example NGINX configuration and the NodeJS server which is proxied by NGINX for a particular resource. The duplication of certain headers caused unexpected behaviour in Chrome-based browsers, so we've updated the Node process to avoid conflicting. * We spent a lot of time improving our integration of OnlyOffice's sheet editor: * The editor is now initialized with your CryptPad account's preferred language. * We realized that our peer-to-peer locking system (which replaces the server-based system provided by OnlyOffice's document server) did not correctly handle multiple locks per user. This caused errors when filtering and sorting columns. We've improved our locking system so these features should now work as expected, but old clients will not understand the new format. As mentioned in the "Update notes" section, admins must follow the recommended update steps to ensure that all clients correctly update to the latest version. From 60979a1f5cbb8a1199c268a128ded51767a430fd Mon Sep 17 00:00:00 2001 From: ansuz Date: Wed, 3 Mar 2021 17:54:58 +0530 Subject: [PATCH 15/27] fix a bad copy-paste in the changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0863a368e..03beab596 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,7 +19,7 @@ Since early in the pandemic we've been serving a custom home page on CryptPad.fr To update from 4.1.0 to 4.2.0: 1. Stop your server -2. Get the latest code from the 4.1.0 tag (`git fetch origin && git checkout 4.1.0`, or just `git pull origin main`) +2. Get the latest code from the 4.2.0 tag (`git fetch origin && git checkout 4.2.0`, or just `git pull origin main`) 3. Install the latest dependencies with `bower update` and `npm i` 4. Restart your server From 321f1d418ff6280b982eda7f38b8d9f2ec9872ed Mon Sep 17 00:00:00 2001 From: yflory Date: Wed, 3 Mar 2021 13:38:32 +0100 Subject: [PATCH 16/27] Fix anonymous drive --- www/common/outer/async-store.js | 1 + 1 file changed, 1 insertion(+) diff --git a/www/common/outer/async-store.js b/www/common/outer/async-store.js index 0a58720ad..091d9a6ad 100644 --- a/www/common/outer/async-store.js +++ b/www/common/outer/async-store.js @@ -2640,6 +2640,7 @@ define([ progress: 0 }); }).nThen(function (waitFor) { + if (typeof(proxy.version) === "undefined") { proxy.version = 11; } Migrate(proxy, waitFor(), function (version, progress) { postMessage(clientId, 'LOADING_DRIVE', { type: 'migrate', From 629eb48562b0a739c318befc18b6cb7193396105 Mon Sep 17 00:00:00 2001 From: yflory Date: Wed, 3 Mar 2021 16:48:25 +0100 Subject: [PATCH 17/27] ??? --- www/common/common-util.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/www/common/common-util.js b/www/common/common-util.js index e98b37009..9ea892702 100644 --- a/www/common/common-util.js +++ b/www/common/common-util.js @@ -269,9 +269,8 @@ Util.magnitudeOfBytes = function (bytes) { if (bytes >= oneGigabyte) { return 'GB'; } - // smallest supported format is MB to preserve existing behaviour - else /* if (bytes >= oneMegabyte) */ { return 'MB'; } - //else { return 'KB'; } + else if (bytes >= oneMegabyte) { return 'MB'; } + else { return 'KB'; } }; // given a path, asynchronously return an arraybuffer From a69fb1fae965ad74e7da994760784bf52af6274f Mon Sep 17 00:00:00 2001 From: yflory Date: Wed, 3 Mar 2021 16:54:25 +0100 Subject: [PATCH 18/27] Disable autostore for owned pads --- www/common/outer/async-store.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/common/outer/async-store.js b/www/common/outer/async-store.js index 0a58720ad..73407f5f9 100644 --- a/www/common/outer/async-store.js +++ b/www/common/outer/async-store.js @@ -1157,7 +1157,7 @@ define([ // Add the pad if it does not exist in our drive if (!contains) { // || (ownedByMe && !inMyDrive)) { var autoStore = Util.find(store.proxy, ['settings', 'general', 'autostore']); - if (autoStore !== 1 && !data.forceSave && !data.path && !ownedByMe) { + if (autoStore !== 1 && !data.forceSave && !data.path) {// && !ownedByMe) { // send event to inner to display the corner popup postMessage(clientId, "AUTOSTORE_DISPLAY_POPUP", { autoStore: autoStore From e7a72896d5d5c6b518a2ddc656048508a1326c80 Mon Sep 17 00:00:00 2001 From: yflory Date: Wed, 3 Mar 2021 16:54:38 +0100 Subject: [PATCH 19/27] Enable properties modal when the pad is not stored --- www/common/common-ui-elements.js | 7 +----- www/common/inner/properties.js | 36 ++++++++++++++++++++----------- www/common/onlyoffice/main.js | 8 +++++++ www/common/sframe-common-outer.js | 11 +++++++++- www/secureiframe/inner.js | 2 +- www/secureiframe/main.js | 1 + 6 files changed, 45 insertions(+), 20 deletions(-) diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index 14c7a298b..104756fac 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -836,12 +836,7 @@ define([ .text(Messages.propertiesButton)) .click(common.prepareFeedback(type)) .click(function () { - common.isPadStored(function (err, data) { - if (!data) { - return void UI.alert(Messages.autostore_notAvailable); - } - sframeChan.event('EV_PROPERTIES_OPEN'); - }); + sframeChan.event('EV_PROPERTIES_OPEN'); }); break; case 'save': // OnlyOffice save diff --git a/www/common/inner/properties.js b/www/common/inner/properties.js index f5780d4c2..ddbf017fc 100644 --- a/www/common/inner/properties.js +++ b/www/common/inner/properties.js @@ -18,6 +18,16 @@ define([ opts = opts || {}; var $d = $('
'); if (!data) { return void cb(void 0, $d); } + data = Util.clone(data); + + var privateData = common.getMetadataMgr().getPrivateData(); + if (privateData.propChannels) { + var p = privateData.propChannels; + data.channel = data.channel || p.channel; + data.rtChannel = data.rtChannel || p.rtChannel; + data.lastVersion = data.lastVersion || p.lastVersion; + data.lastCpHash = data.lastCpHash || p.lastCpHash; + } if (data.channel) { $('