From 31414ca7b0690fc9c410ba9bb43bb4786f4851f9 Mon Sep 17 00:00:00 2001 From: yflory Date: Fri, 19 Mar 2021 15:09:05 +0100 Subject: [PATCH 1/7] Fix degraded mode not set when multiple tabs on the same pad --- www/common/outer/cursor.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/www/common/outer/cursor.js b/www/common/outer/cursor.js index b6662b75f..8338fef16 100644 --- a/www/common/outer/cursor.js +++ b/www/common/outer/cursor.js @@ -50,6 +50,12 @@ define([ }); }; + var updateDegraded = function (ctx, wc, chan) { + var m = wc.members; + chan.degraded = (m.length-1) >= DEGRADED; + ctx.emit('DEGRADED', { degraded: chan.degraded }, chan.clients); + }; + var initCursor = function (ctx, obj, client, cb) { var channel = obj.channel; var secret = obj.secret; @@ -92,14 +98,10 @@ define([ // ==> And push the new tab to the list chan.clients.push(client); + updateDegraded(ctx, chan.wc, chan); return void cb(); } - var updateDegraded = function (ctx, wc, chan) { - var m = wc.members; - chan.degraded = (m.length-1) >= DEGRADED; - ctx.emit('DEGRADED', { degraded: chan.degraded }, chan.clients); - }; var onOpen = function (wc) { ctx.channels[channel] = ctx.channels[channel] || {}; From 3e969dd9a5e52c38aa997f25a8de13e3f16ade2a Mon Sep 17 00:00:00 2001 From: yflory Date: Fri, 19 Mar 2021 15:09:28 +0100 Subject: [PATCH 2/7] Fix noDrive uid always modified --- www/common/outer/async-store.js | 11 +++++++++-- www/debug/main.js | 1 + 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/www/common/outer/async-store.js b/www/common/outer/async-store.js index 60dc9ca73..d4f49014f 100644 --- a/www/common/outer/async-store.js +++ b/www/common/outer/async-store.js @@ -586,11 +586,14 @@ define([ var proxy = store.proxy || {}; var disableThumbnails = Util.find(proxy, ['settings', 'general', 'disableThumbnails']); var teams = (store.modules['team'] && store.modules['team'].getTeamsData(app)) || {}; + if (!proxy.uid) { + store.noDriveUid = store.noDriveUid || Hash.createChannelId(); + } var metadata = { // "user" is shared with everybody via the userlist user: { name: proxy[Constants.displayNameKey] || store.noDriveName || "", - uid: proxy.uid || Hash.createChannelId(), // Random uid in nodrive mode + uid: proxy.uid || store.noDriveUid, // Random uid in nodrive mode avatar: Util.find(proxy, ['profile', 'avatar']), profile: Util.find(proxy, ['profile', 'view']), color: getUserColor(), @@ -858,6 +861,7 @@ define([ Store.setDisplayName = function (clientId, value, cb) { if (!store.proxy) { store.noDriveName = value; + broadcast([clientId], "UPDATE_METADATA"); return void cb(); } if (store.modules['profile']) { @@ -2836,7 +2840,10 @@ define([ store.driveMetadata = info.metadata; if (!rt.proxy.drive || typeof(rt.proxy.drive) !== 'object') { rt.proxy.drive = {}; } if (!rt.proxy[Constants.displayNameKey] && store.noDriveName) { - store.proxy[Constants.displayNameKey] = store.noDriveName; + rt.proxy[Constants.displayNameKey] = store.noDriveName; + } + if (!rt.proxy.uid && store.noDriveUid) { + rt.proxy.uid = store.noDriveUid; } /* // deprecating localStorage migration as of 4.2.0 diff --git a/www/debug/main.js b/www/debug/main.js index 9053dfbf6..6f855e1db 100644 --- a/www/debug/main.js +++ b/www/debug/main.js @@ -44,6 +44,7 @@ define([ meta.debugDrive = drive; }; SFCommonO.start({ + noDrive: true, addData:addData }); }); From 9980346ef7947acaa19483e6bd39cb1c28045106 Mon Sep 17 00:00:00 2001 From: yflory Date: Fri, 19 Mar 2021 15:19:57 +0100 Subject: [PATCH 3/7] Set degraded mode limit in AppConfig --- www/common/application_config_internal.js | 11 +++++++++++ www/common/outer/cursor.js | 6 ++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/www/common/application_config_internal.js b/www/common/application_config_internal.js index 496e65f1f..f91c73f56 100644 --- a/www/common/application_config_internal.js +++ b/www/common/application_config_internal.js @@ -179,5 +179,16 @@ define(function() { // You can change the value here. // config.maxOwnedTeams = 5; + // The userlist displayed in collaborative documents is stored alongside the document data. + // Everytime someone with edit rights joins a document or modify their user data (display + // name, avatar, color, etc.), they update the "userlist" part of the document. When too many + // editors are in the same document, all these changes increase the risks of conflicts which + // require CPU time to solve. A "degraded" mode can now be set when a certain number of editors + // are in a document at the same time. This mode disables the userlist, the chat and the + // position of other users' cursor. You can configure the number of user from which the session + // will enter into degraded mode. A big number may result in collaborative edition being broken, + // but this number depends on the network and CPU performances of each user's device. + config.degradedLimit = 8; + return config; }); diff --git a/www/common/outer/cursor.js b/www/common/outer/cursor.js index 8338fef16..371a4565e 100644 --- a/www/common/outer/cursor.js +++ b/www/common/outer/cursor.js @@ -2,11 +2,13 @@ define([ '/common/common-util.js', '/common/common-constants.js', '/customize/messages.js', + '/customize/application_config.js', '/bower_components/chainpad-crypto/crypto.js', -], function (Util, Constants, Messages, Crypto) { +], function (Util, Constants, Messages, AppConfig, Crypto) { var Cursor = {}; - var DEGRADED = 3; // XXX Number of users before switching to degraded mode + var DEGRADED = AppConfig.degradedLimit || 8; +console.log(DEGRADED); var convertToUint8 = function (obj) { var l = Object.keys(obj).length; From 86e50e04775aad51c89a92440426233c82b909fd Mon Sep 17 00:00:00 2001 From: yflory Date: Fri, 19 Mar 2021 17:05:28 +0100 Subject: [PATCH 4/7] Add a configuration key to disable driveless mode --- www/common/application_config_internal.js | 8 ++++++++ www/common/sframe-common-outer.js | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/www/common/application_config_internal.js b/www/common/application_config_internal.js index f91c73f56..e119b3e5e 100644 --- a/www/common/application_config_internal.js +++ b/www/common/application_config_internal.js @@ -190,5 +190,13 @@ define(function() { // but this number depends on the network and CPU performances of each user's device. config.degradedLimit = 8; + // In "legacy" mode, one-time users were always creating an "anonymous" drive when visiting CryptPad + // in which they could store their pads. The new "driveless" mode allow users to open an existing + // pad without creating a drive in the background. The drive will only be created if they visit + // a different page (Drive, Settings, etc.) or try to create a new pad themselves. You can disable + // the driveless mode by changing the following value to "false" + config.allowDrivelessMode = true; + config.allowDrivelessMode = true; + return config; }); diff --git a/www/common/sframe-common-outer.js b/www/common/sframe-common-outer.js index df49ee6a3..77aa9ba43 100644 --- a/www/common/sframe-common-outer.js +++ b/www/common/sframe-common-outer.js @@ -222,7 +222,7 @@ define([ } catch (e) { console.error(e); } Cryptpad.ready(waitFor(), { - noDrive: cfg.noDrive, + noDrive: cfg.noDrive && AppConfig.allowDrivelessMode, driveEvents: cfg.driveEvents, cache: Boolean(cfg.cache), currentPad: currentPad From 18e995f63a8a75a145b389099d02160db8567ddd Mon Sep 17 00:00:00 2001 From: yflory Date: Fri, 19 Mar 2021 17:08:11 +0100 Subject: [PATCH 5/7] Add the degraded threshold value to the translation key in toolbar --- www/common/outer/cursor.js | 1 - www/common/toolbar.js | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/www/common/outer/cursor.js b/www/common/outer/cursor.js index 371a4565e..95b2b34c6 100644 --- a/www/common/outer/cursor.js +++ b/www/common/outer/cursor.js @@ -8,7 +8,6 @@ define([ var Cursor = {}; var DEGRADED = AppConfig.degradedLimit || 8; -console.log(DEGRADED); var convertToUint8 = function (obj) { var l = Object.keys(obj).length; diff --git a/www/common/toolbar.js b/www/common/toolbar.js index c42aa36cb..aafc356a5 100644 --- a/www/common/toolbar.js +++ b/www/common/toolbar.js @@ -212,6 +212,7 @@ MessengerUI, Messages) { var $editUsersList = $('
', {'class': 'cp-toolbar-userlist-others'}) .appendTo($editUsers); + var degradedLimit = Config.degradedLimit || 8; if (!online) { $('').text(Messages.userlist_offline).appendTo($editUsersList); numberOfEditUsers = '?'; @@ -219,8 +220,7 @@ MessengerUI, Messages) { } else if (metadataMgr.isDegraded() === true) { numberOfEditUsers = Math.max(metadataMgr.getChannelMembers().length - 1, 0); numberOfViewUsers = ''; - Messages.toolbar_degraded = "Too many editors are present in the pad. The userlist has been disabled to improve performances"; // XXX - $('').text(Messages.toolbar_degraded).appendTo($editUsersList); + $('').text(Messages._getKey('toolbar_degraded', [degradedLimit])).appendTo($editUsersList); } // Update the buttons From c168393c21559d785fbd8e8938eb457a8bf553e9 Mon Sep 17 00:00:00 2001 From: yflory Date: Fri, 19 Mar 2021 17:14:40 +0100 Subject: [PATCH 6/7] Only allow driveless mode for existing pads --- www/common/sframe-common-outer.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/www/common/sframe-common-outer.js b/www/common/sframe-common-outer.js index 77aa9ba43..e74fb882c 100644 --- a/www/common/sframe-common-outer.js +++ b/www/common/sframe-common-outer.js @@ -221,8 +221,11 @@ define([ } } catch (e) { console.error(e); } + // NOTE: Driveless mode should only work for existing pads, but we can't check that + // before creating the worker because we need the anon RPC to do so. + // We're only going to check if a hash exists in the URL or not. Cryptpad.ready(waitFor(), { - noDrive: cfg.noDrive && AppConfig.allowDrivelessMode, + noDrive: cfg.noDrive && AppConfig.allowDrivelessMode && currentPad.hash, driveEvents: cfg.driveEvents, cache: Boolean(cfg.cache), currentPad: currentPad From c6b8b11dc3c18c7b55ef3646970665b969b3067a Mon Sep 17 00:00:00 2001 From: yflory Date: Fri, 19 Mar 2021 18:10:27 +0100 Subject: [PATCH 7/7] Fix Destroy and change password when pad not stored --- www/common/cryptpad-common.js | 16 ++++++++++++---- www/common/inner/access.js | 11 +++++++++-- www/common/outer/async-store.js | 2 ++ www/common/proxy-manager.js | 15 ++++++++++++--- www/common/sframe-common-outer.js | 1 + www/secureiframe/main.js | 1 + 6 files changed, 37 insertions(+), 9 deletions(-) diff --git a/www/common/cryptpad-common.js b/www/common/cryptpad-common.js index 31c65bb86..f4419d2cb 100644 --- a/www/common/cryptpad-common.js +++ b/www/common/cryptpad-common.js @@ -1095,6 +1095,7 @@ define([ common.changePadPassword = function (Crypt, Crypto, data, cb) { var href = data.href; + var oldPassword = data.oldPassword; var newPassword = data.password; var teamId = data.teamId; if (!href) { return void cb({ error: 'EINVAL_HREF' }); } @@ -1123,7 +1124,9 @@ define([ var isSharedFolder = parsed.type === 'drive'; - var optsGet = {}; + var optsGet = { + password: oldPassword + }; var optsPut = { password: newPassword, metadata: {}, @@ -1133,7 +1136,7 @@ define([ var cryptgetVal; Nthen(function (waitFor) { - if (parsed.hashData && parsed.hashData.password) { + if (parsed.hashData && parsed.hashData.password && !oldPassword) { common.getPadAttribute('password', waitFor(function (err, password) { optsGet.password = password; }), href); @@ -1418,6 +1421,7 @@ define([ common.changeOOPassword = function (data, _cb) { var cb = Util.once(Util.mkAsync(_cb)); var href = data.href; + var oldPassword = data.oldPassword; var newPassword = data.password; var teamId = data.teamId; if (!href) { return void cb({ error: 'EINVAL_HREF' }); } @@ -1452,12 +1456,16 @@ define([ validateKey: newSecret.keys.validateKey }, }; - var optsGet = {}; + var optsGet = { + password: oldPassword + }; Nthen(function (waitFor) { common.getPadAttribute('', waitFor(function (err, _data) { padData = _data; - optsGet.password = padData.password; + if (!oldPassword) { + optsGet.password = padData.password; + } }), href); common.getAccessKeys(waitFor(function (keys) { optsGet.accessKeys = keys; diff --git a/www/common/inner/access.js b/www/common/inner/access.js index 3bbef91e9..a09f98bfb 100644 --- a/www/common/inner/access.js +++ b/www/common/inner/access.js @@ -888,9 +888,16 @@ define([ }); } + var href = data.href; + var hashes = priv.hashes || {}; + var bestHash = hashes.editHash || hashes.viewHash || hashes.fileHash; + if (data.fakeHref) { + href = Hash.hashToHref(bestHash, priv.app); + } sframeChan.query(q, { teamId: typeof(owned) !== "boolean" ? owned : undefined, - href: data.href, + href: href, + oldPassword: priv.password, password: newPass }, function (err, data) { $(passwordOk).text(Messages.properties_changePasswordButton); @@ -956,7 +963,7 @@ define([ spinner.spin(); sframeChan.query('Q_DELETE_OWNED', { teamId: typeof(owned) !== "boolean" ? owned : undefined, - channel: data.channel + channel: data.channel || priv.channel }, function (err, obj) { spinner.done(); UI.findCancelButton().click(); diff --git a/www/common/outer/async-store.js b/www/common/outer/async-store.js index d4f49014f..8ac1a77c3 100644 --- a/www/common/outer/async-store.js +++ b/www/common/outer/async-store.js @@ -331,6 +331,8 @@ define([ teamId = data.teamId; } + // XXX CLEAR CACHE + if (channel === store.driveChannel && !force) { return void cb({error: 'User drive removal blocked!'}); } diff --git a/www/common/proxy-manager.js b/www/common/proxy-manager.js index 7093f0ec5..011ec4f36 100644 --- a/www/common/proxy-manager.js +++ b/www/common/proxy-manager.js @@ -868,7 +868,6 @@ define([ if (fId && Env.folders[fId] && Env.folders[fId].deleting) { delete Env.folders[fId].deleting; } - console.error(obj.error, chan); Feedback.send('ERROR_DELETING_OWNED_PAD=' + chan + '|' + obj.error, true); return void cb(); } @@ -881,6 +880,11 @@ define([ ids.push(fId); } + if (!ids.length) { + toDelete = undefined; + return void cb(); + } + ids.forEach(function (id) { var paths = findFile(Env, id); var _resolved = _resolvePaths(Env, paths); @@ -912,8 +916,13 @@ define([ }); }); }).nThen(function () { - // Remove deleted pads from the drive - _delete(Env, { resolved: toDelete }, cb); + if (!toDelete) { + // Nothing to delete + cb(); + } else { + // Remove deleted pads from the drive + _delete(Env, { resolved: toDelete }, cb); + } // If we were using the access modal, send a refresh command if (data.channel) { Env.Store.refreshDriveUI(); diff --git a/www/common/sframe-common-outer.js b/www/common/sframe-common-outer.js index e74fb882c..687d3a54b 100644 --- a/www/common/sframe-common-outer.js +++ b/www/common/sframe-common-outer.js @@ -1407,6 +1407,7 @@ define([ }; config.data = { app: parsed.type, + channel: secret.channel, hashes: hashes, password: password, isTemplate: isTemplate, diff --git a/www/secureiframe/main.js b/www/secureiframe/main.js index bb7f05cca..be026194e 100644 --- a/www/secureiframe/main.js +++ b/www/secureiframe/main.js @@ -101,6 +101,7 @@ define([ origin: window.location.origin, pathname: window.location.pathname, feedbackAllowed: Utils.Feedback.state, + channel: config.data.channel, hashes: config.data.hashes, password: config.data.password, propChannels: config.data.getPropChannels(),