From ad42d956d7cfea8ce7ce2fbdf92e218114cfba40 Mon Sep 17 00:00:00 2001 From: yflory Date: Mon, 21 Oct 2019 11:10:30 +0200 Subject: [PATCH 01/10] Add support for Japanese translation --- customize.dist/translations/messages.ja.js | 14 ++++++++++++++ www/common/translations/messages.ja.json | 1 + 2 files changed, 15 insertions(+) create mode 100644 customize.dist/translations/messages.ja.js create mode 100644 www/common/translations/messages.ja.json diff --git a/customize.dist/translations/messages.ja.js b/customize.dist/translations/messages.ja.js new file mode 100644 index 000000000..7293bfc50 --- /dev/null +++ b/customize.dist/translations/messages.ja.js @@ -0,0 +1,14 @@ +/* + * You can override the translation text using this file. + * The recommended method is to make a copy of this file (/customize.dist/translations/messages.{LANG}.js) + in a 'customize' directory (/customize/translations/messages.{LANG}.js). + * If you want to check all the existing translation keys, you can open the internal language file + but you should not change it directly (/common/translations/messages.{LANG}.js) +*/ +define(['/common/translations/messages.ja.js'], function (Messages) { + // Replace the existing keys in your copied file here: + // Messages.button_newpad = "New Rich Text Document"; + + return Messages; +}); + diff --git a/www/common/translations/messages.ja.json b/www/common/translations/messages.ja.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/www/common/translations/messages.ja.json @@ -0,0 +1 @@ +{} From c894351a3042aaac36be9b541c3362c99a6deb4e Mon Sep 17 00:00:00 2001 From: yflory Date: Tue, 22 Oct 2019 11:21:41 +0200 Subject: [PATCH 02/10] Fix pinning issue causing unnecessary reset --- www/common/cryptpad-common.js | 6 ++++-- www/common/outer/async-store.js | 14 ++++++++++++++ www/common/outer/store-rpc.js | 1 + 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/www/common/cryptpad-common.js b/www/common/cryptpad-common.js index 5d65e92b6..f0def2f9c 100644 --- a/www/common/cryptpad-common.js +++ b/www/common/cryptpad-common.js @@ -996,8 +996,10 @@ define([ } })); if (!isSharedFolder) { - common.unpinPads([oldChannel], waitFor(), teamId); - common.pinPads([newSecret.channel], waitFor(), teamId); + postMessage("CHANGE_PAD_PASSWORD_PIN", { + oldChannel: oldChannel, + channel: newSecret.channel + }, waitFor()); } }).nThen(function () { cb({ diff --git a/www/common/outer/async-store.js b/www/common/outer/async-store.js index cf382caff..1e419548a 100644 --- a/www/common/outer/async-store.js +++ b/www/common/outer/async-store.js @@ -1547,6 +1547,20 @@ define([ channel.sendMessage(msg, clientId, cb); }; + // Unpin and pin the new channel in all team when changing a pad password + Store.changePadPasswordPin = function (clientId, data, cb) { + var oldChannel = data.oldChannel; + var channel = data.channel; + nThen(function (waitFor) { + getAllStores().forEach(function (s) { + var allData = s.manager.findChannel(channel); + if (!allData.length) { return; } + s.rpc.unpin([oldChannel], waitFor()); + s.rpc.pin([channel], waitFor()); + }); + }).nThen(cb); + }; + // requestPadAccess is used to check if we have a way to contact the owner // of the pad AND to send the request if we want // data.send === false ==> check if we can contact them diff --git a/www/common/outer/store-rpc.js b/www/common/outer/store-rpc.js index 9accc5f29..2ef490876 100644 --- a/www/common/outer/store-rpc.js +++ b/www/common/outer/store-rpc.js @@ -79,6 +79,7 @@ define([ GIVE_PAD_ACCESS: Store.givePadAccess, GET_PAD_METADATA: Store.getPadMetadata, SET_PAD_METADATA: Store.setPadMetadata, + CHANGE_PAD_PASSWORD_PIN: Store.changePadPasswordPin, // Drive DRIVE_USEROBJECT: Store.userObjectCommand, // Settings, From 427cf836b11fe86333226a6980457f17865b91a5 Mon Sep 17 00:00:00 2001 From: yflory Date: Tue, 22 Oct 2019 12:04:30 +0200 Subject: [PATCH 03/10] Improve password change workflow --- www/common/drive-ui.js | 6 ++++++ www/common/outer/async-store.js | 11 ++++++++++- www/common/proxy-manager.js | 3 +++ www/common/sframe-common-outer.js | 24 ++++++++++++++++++++---- www/common/userObject.js | 8 ++++---- 5 files changed, 43 insertions(+), 9 deletions(-) diff --git a/www/common/drive-ui.js b/www/common/drive-ui.js index ec7245885..072f144fa 100644 --- a/www/common/drive-ui.js +++ b/www/common/drive-ui.js @@ -1857,6 +1857,12 @@ define([ $span.addClass('cp-app-drive-element-sharedf'); _addOwnership($span, $state, data); + var hrefData = Hash.parsePadUrl(data.href || data.roHref); + if (hrefData.hashData && hrefData.hashData.password) { + var $password = $passwordIcon.clone().appendTo($state); + $password.attr('title', Messages.fm_passwordProtected || ''); + } + var $shared = $sharedIcon.clone().appendTo($state); $shared.attr('title', Messages.fm_canBeShared); } diff --git a/www/common/outer/async-store.js b/www/common/outer/async-store.js index 1e419548a..eaa019384 100644 --- a/www/common/outer/async-store.js +++ b/www/common/outer/async-store.js @@ -1919,7 +1919,7 @@ define([ store.manager.user.userObject.getHref(data) : data.href; var parsed = Hash.parsePadUrl(href); var secret = Hash.getSecrets(parsed.type, parsed.hash, o); - SF.updatePassword({ + SF.updatePassword(Store, { oldChannel: secret.channel, password: n, href: href @@ -2063,6 +2063,15 @@ define([ /////////////////////// Init ///////////////////////////////////// ////////////////////////////////////////////////////////////////// + Store.refreshDriveUI = function () { + getAllStores().forEach(function (_s) { + var send = _s.id ? _s.sendEvent : sendDriveEvent; + send('DRIVE_CHANGE', { + path: ['drive', UserObject.FILES_DATA] + }); + }); + }; + var onReady = function (clientId, returned, cb) { var proxy = store.proxy; var unpin = function (data, cb) { diff --git a/www/common/proxy-manager.js b/www/common/proxy-manager.js index aae33e6d8..cf7f7d78b 100644 --- a/www/common/proxy-manager.js +++ b/www/common/proxy-manager.js @@ -49,6 +49,9 @@ define([ var deprecateProxy = function (Env, id, channel) { Env.unpinPads([channel], function () {}); Env.user.userObject.deprecateSharedFolder(id); + if (Env.Store && Env.Store.refreshDriveUI) { + Env.Store.refreshDriveUI(); + } }; /* diff --git a/www/common/sframe-common-outer.js b/www/common/sframe-common-outer.js index 87b477d5c..84c08416a 100644 --- a/www/common/sframe-common-outer.js +++ b/www/common/sframe-common-outer.js @@ -215,8 +215,15 @@ define([ if (wrongPasswordStored) { // Store the correct password nThen(function (w) { + // XXX noPasswordStored: return; ? Cryptpad.setPadAttribute('password', password, w(), parsed.getUrl()); Cryptpad.setPadAttribute('channel', secret.channel, w(), parsed.getUrl()); + if (parsed.hashData.mode === 'edit') { + var href = window.location.pathname + '#' + Utils.Hash.getEditHashFromKeys(secret); + Cryptpad.setPadAttribute('href', href, w(), parsed.getUrl()); + var roHref = window.location.pathname + '#' + Utils.Hash.getViewHashFromKeys(secret); + Cryptpad.setPadAttribute('roHref', roHref, w(), parsed.getUrl()); + } }).nThen(correctPassword); } else { correctPassword(); @@ -244,10 +251,19 @@ define([ } password = val; - Cryptpad.getFileSize(window.location.href, password, waitFor(function (e, size) { - if (size !== 0) { - return void todo(); - } + if (parsed.type === "file") { + // `isNewChannel` doesn't work for files (not a channel) + // `getFileSize` is not adapted to channels because of metadata + Cryptpad.getFileSize(window.location.href, password, waitFor(function (e, size) { + if (size !== 0) { return void todo(); } + // Wrong password or deleted file? + askPassword(true); + })); + return; + } + // Not a file, so we can use `isNewChannel` + Cryptpad.isNewChannel(window.location.href, password, waitFor(function(e, isNew) { + if (!isNew) { return void todo(); } if (parsed.hashData.mode === 'view' && (val || !parsed.hashData.password)) { // Error, wrong password stored, the view seed has changed with the password // password will never work diff --git a/www/common/userObject.js b/www/common/userObject.js index 398ebe301..7a81e220f 100644 --- a/www/common/userObject.js +++ b/www/common/userObject.js @@ -385,8 +385,8 @@ define([ var result; var noPassword = function (str) { if (!str) { return; } - var value = str.replace(/\/p\/?/, '/'); - return Hash.getRelativeHref(value); + var parsed = Hash.parsePadUrl(str); + return parsed.getUrl().replace(/\/p\/?/, '/'); }; var href = noPassword(_href); getFiles([FILES_DATA]).some(function (id) { @@ -403,8 +403,8 @@ define([ var result; var noPassword = function (str) { if (!str) { return; } - var value = str.replace(/\/p\/?/, '/'); - return Hash.getRelativeHref(value); + var parsed = Hash.parsePadUrl(str); + return parsed.getUrl().replace(/\/p\/?/, '/'); }; var href = noPassword(_href); getFiles([SHARED_FOLDERS]).some(function (id) { From fa2ad4e476107fdd8e215ff859370bef0188aad0 Mon Sep 17 00:00:00 2001 From: yflory Date: Tue, 22 Oct 2019 13:06:21 +0200 Subject: [PATCH 04/10] Add /p/ to the hash when adding a password --- www/common/outer/async-store.js | 5 ++--- www/common/sframe-common-outer.js | 11 ++++++++++- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/www/common/outer/async-store.js b/www/common/outer/async-store.js index eaa019384..cc94e9d25 100644 --- a/www/common/outer/async-store.js +++ b/www/common/outer/async-store.js @@ -1531,8 +1531,7 @@ define([ Store.leavePad = function (clientId, data, cb) { var channel = channels[data.channel]; if (!channel || !channel.cpNf) { return void cb ({error: 'EINVAL'}); } - channel.cpNf.stop(); - delete channels[data.channel]; + Store.dropChannel(data.channel); cb(); }; Store.sendPadMsg = function (clientId, data, cb) { @@ -1850,7 +1849,7 @@ define([ // Clients management var driveEventClients = []; - var dropChannel = function (chanId) { + var dropChannel = Store.dropChannel = function (chanId) { try { store.messenger.leavePad(chanId); } catch (e) { console.error(e); } diff --git a/www/common/sframe-common-outer.js b/www/common/sframe-common-outer.js index 84c08416a..431e274bb 100644 --- a/www/common/sframe-common-outer.js +++ b/www/common/sframe-common-outer.js @@ -174,7 +174,16 @@ define([ var parsed = Utils.Hash.parsePadUrl(window.location.href); var todo = function () { secret = Utils.secret = Utils.Hash.getSecrets(parsed.type, void 0, password); - Cryptpad.getShareHashes(secret, waitFor(function (err, h) { hashes = h; })); + Cryptpad.getShareHashes(secret, waitFor(function (err, h) { + hashes = h; + if (password && !parsed.hashData.password) { + var ohc = window.onhashchange; + window.onhashchange = function () {}; + window.location.hash = h.fileHash || h.editHash || h.viewHash || window.location.hash; + window.onhashchange = ohc; + ohc({reset: true}); + } + })); }; if (!parsed.hashData) { // No hash, no need to check for a password From 639d5f0f7c51ebbda58778b9c9d8427ac70689a9 Mon Sep 17 00:00:00 2001 From: Weblate Date: Tue, 22 Oct 2019 12:53:17 +0000 Subject: [PATCH 05/10] Translated using Weblate (English) Currently translated at 100.0% (1131 of 1131 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 100.0% (1130 of 1130 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 100.0% (1129 of 1129 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 100.0% (1128 of 1128 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ --- www/common/translations/messages.json | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/www/common/translations/messages.json b/www/common/translations/messages.json index a811b3e1b..e45b7dec4 100644 --- a/www/common/translations/messages.json +++ b/www/common/translations/messages.json @@ -1221,5 +1221,9 @@ "team_title": "Team: {0}", "team_quota": "Your team's storage limit", "drive_quota": "Your storage limit", - "settings_codeBrackets": "Auto-close brackets" + "settings_codeBrackets": "Auto-close brackets", + "team_viewers": "Viewers", + "drive_sfPassword": "Your shared folder {0} is no longer available. It has either been deleted by its owner or it is now protected with a new password. You can remove this folder from your CryptDrive, or recover access using the new password.", + "drive_sfPasswordError": "Wrong password", + "password_error_seed": "Pad not found!
This error can be caused by two factors: either a password was added/changed, or the pad has been deleted from the server." } From d7f9adf19b230fe122ecaaa212b2366573c13613 Mon Sep 17 00:00:00 2001 From: Weblate Date: Tue, 22 Oct 2019 12:53:18 +0000 Subject: [PATCH 06/10] Translated using Weblate (French) Currently translated at 100.0% (1131 of 1131 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/fr/ --- www/common/translations/messages.fr.json | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/www/common/translations/messages.fr.json b/www/common/translations/messages.fr.json index 2e4574c72..8c9f7a476 100644 --- a/www/common/translations/messages.fr.json +++ b/www/common/translations/messages.fr.json @@ -1221,5 +1221,9 @@ "team_title": "Équipe : {0}", "team_quota": "Limite de stockage de votre équipe", "drive_quota": "Votre limite de stockage", - "settings_codeBrackets": "Fermer automatiquement les parenthèses" + "settings_codeBrackets": "Fermer automatiquement les parenthèses", + "team_viewers": "Lecteurs", + "drive_sfPassword": "Votre dossier partagé {0} n'est plus disponible. Il a soit été supprimé par son propriétaire ou il est protégé par un nouveau mot de passe. Vous pouvez supprimer ce dossier de votre CryptDrive ou retrouver l'accès en tapant le nouveau mot de passe.", + "drive_sfPasswordError": "Mot de passe incorrect", + "password_error_seed": "Pad introuvable !
Cette erreur peut provenir de deux facteurs. Soit un mot de passe a été ajouté ou modifié, soit le pad a été supprimé par son propriétaire." } From 550965b1c8367a5aaac49254087bf79f23f95262 Mon Sep 17 00:00:00 2001 From: yflory Date: Tue, 22 Oct 2019 15:22:43 +0200 Subject: [PATCH 07/10] Password change UI --- www/common/common-ui-elements.js | 8 ++- www/common/sframe-common-outer.js | 114 +++++++++++++++++------------- 2 files changed, 70 insertions(+), 52 deletions(-) diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index 9d51f5500..2f7261326 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -564,14 +564,18 @@ define([ newPassword, passwordOk ]); + var pLocked = false; $(passwordOk).click(function () { var newPass = $(newPassword).find('input').val(); if (data.password === newPass || (!data.password && !newPass)) { return void UI.alert(Messages.properties_passwordSame); } + if (pLocked) { return; } + pLocked = true; UI.confirm(changePwConfirm, function (yes) { - if (!yes) { return; } + if (!yes) { pLocked = false; return; } + $(passwordOk).html('').append(h('span.fa.fa-spinner.fa-spin', {style: 'margin-left: 0'})); sframeChan.query("Q_PAD_PASSWORD_CHANGE", { teamId: typeof(owned) !== "boolean" ? owned : undefined, href: data.href || data.roHref, @@ -579,6 +583,8 @@ define([ }, function (err, data) { if (err || data.error) { console.error(err || data.error); + pLocked = false; + $(passwordOk).text(Messages.properties_changePasswordButton); return void UI.alert(Messages.properties_passwordError); } UI.findOKButton().click(); diff --git a/www/common/sframe-common-outer.js b/www/common/sframe-common-outer.js index 431e274bb..542b1b69b 100644 --- a/www/common/sframe-common-outer.js +++ b/www/common/sframe-common-outer.js @@ -206,64 +206,72 @@ define([ // 2c: 'view' pad and '/p/' and a wrong password stored --> the seed is incorrect // 2d: 'view' pad and '/p/' and password never stored (security feature) --> password-prompt - Cryptpad.getPadAttribute('password', waitFor(function (err, val) { - var askPassword = function (wrongPasswordStored) { - // Ask for the password and check if the pad exists - // If the pad doesn't exist, it means the password isn't correct - // or the pad has been deleted - var correctPassword = waitFor(); - sframeChan.on('Q_PAD_PASSWORD_VALUE', function (data, cb) { - password = data; - var next = function (e, isNew) { - if (Boolean(isNew)) { - // Ask again in the inner iframe - // We should receive a new Q_PAD_PASSWORD_VALUE - cb(false); + var askPassword = function (wrongPasswordStored) { + // Ask for the password and check if the pad exists + // If the pad doesn't exist, it means the password isn't correct + // or the pad has been deleted + var correctPassword = waitFor(); + sframeChan.on('Q_PAD_PASSWORD_VALUE', function (data, cb) { + password = data; + var next = function (e, isNew) { + if (Boolean(isNew)) { + // Ask again in the inner iframe + // We should receive a new Q_PAD_PASSWORD_VALUE + cb(false); + } else { + todo(); + if (wrongPasswordStored) { + // Store the correct password + nThen(function (w) { + // XXX noPasswordStored: return; ? + Cryptpad.setPadAttribute('password', password, w(), parsed.getUrl()); + Cryptpad.setPadAttribute('channel', secret.channel, w(), parsed.getUrl()); + if (parsed.hashData.mode === 'edit') { + var href = window.location.pathname + '#' + Utils.Hash.getEditHashFromKeys(secret); + Cryptpad.setPadAttribute('href', href, w(), parsed.getUrl()); + var roHref = window.location.pathname + '#' + Utils.Hash.getViewHashFromKeys(secret); + Cryptpad.setPadAttribute('roHref', roHref, w(), parsed.getUrl()); + } + }).nThen(correctPassword); } else { - todo(); - if (wrongPasswordStored) { - // Store the correct password - nThen(function (w) { - // XXX noPasswordStored: return; ? - Cryptpad.setPadAttribute('password', password, w(), parsed.getUrl()); - Cryptpad.setPadAttribute('channel', secret.channel, w(), parsed.getUrl()); - if (parsed.hashData.mode === 'edit') { - var href = window.location.pathname + '#' + Utils.Hash.getEditHashFromKeys(secret); - Cryptpad.setPadAttribute('href', href, w(), parsed.getUrl()); - var roHref = window.location.pathname + '#' + Utils.Hash.getViewHashFromKeys(secret); - Cryptpad.setPadAttribute('roHref', roHref, w(), parsed.getUrl()); - } - }).nThen(correctPassword); - } else { - correctPassword(); - } - cb(true); + correctPassword(); } - }; - if (parsed.type === "file") { - // `isNewChannel` doesn't work for files (not a channel) - // `getFileSize` is not adapted to channels because of metadata - Cryptpad.getFileSize(window.location.href, password, function (e, size) { - next(e, size === 0); - }); - return; + cb(true); } - // Not a file, so we can use `isNewChannel` - Cryptpad.isNewChannel(window.location.href, password, next); - }); - sframeChan.event("EV_PAD_PASSWORD"); - }; + }; + if (parsed.type === "file") { + // `isNewChannel` doesn't work for files (not a channel) + // `getFileSize` is not adapted to channels because of metadata + Cryptpad.getFileSize(window.location.href, password, function (e, size) { + next(e, size === 0); + }); + return; + } + // Not a file, so we can use `isNewChannel` + Cryptpad.isNewChannel(window.location.href, password, next); + }); + sframeChan.event("EV_PAD_PASSWORD"); + }; - if (!val && sessionStorage.newPadPassword) { - val = sessionStorage.newPadPassword; + var done = waitFor(); + var stored = false; + nThen(function (w) { + Cryptpad.getPadAttribute('title', w(function (err, data) { + stored = (!err && typeof (data) === "string"); + })); + Cryptpad.getPadAttribute('password', w(function (err, val) { + password = val; + }), parsed.getUrl()); + }).nThen(function (w) { + if (!password && sessionStorage.newPadPassword) { + password = sessionStorage.newPadPassword; delete sessionStorage.newPadPassword; } - password = val; if (parsed.type === "file") { // `isNewChannel` doesn't work for files (not a channel) // `getFileSize` is not adapted to channels because of metadata - Cryptpad.getFileSize(window.location.href, password, waitFor(function (e, size) { + Cryptpad.getFileSize(window.location.href, password, w(function (e, size) { if (size !== 0) { return void todo(); } // Wrong password or deleted file? askPassword(true); @@ -271,19 +279,23 @@ define([ return; } // Not a file, so we can use `isNewChannel` - Cryptpad.isNewChannel(window.location.href, password, waitFor(function(e, isNew) { + Cryptpad.isNewChannel(window.location.href, password, w(function(e, isNew) { if (!isNew) { return void todo(); } - if (parsed.hashData.mode === 'view' && (val || !parsed.hashData.password)) { + 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 sframeChan.event("EV_PAD_PASSWORD_ERROR"); waitFor.abort(); return; } + if (!stored && !parsed.hashData.password) { + // We've received a link without /p/ and it doesn't work without a password: abort + return void todo(); + } // Wrong password or deleted file? askPassword(true); })); - }), parsed.getUrl()); + }).nThen(done); } }).nThen(function (waitFor) { if (cfg.afterSecrets) { From e75e22fb10a5c71ce50c217e1e258f848f295525 Mon Sep 17 00:00:00 2001 From: yflory Date: Tue, 22 Oct 2019 15:45:31 +0200 Subject: [PATCH 08/10] Fix sessionStorage bug with pad password change --- www/common/sframe-common-outer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/common/sframe-common-outer.js b/www/common/sframe-common-outer.js index 542b1b69b..722de0607 100644 --- a/www/common/sframe-common-outer.js +++ b/www/common/sframe-common-outer.js @@ -263,7 +263,7 @@ define([ password = val; }), parsed.getUrl()); }).nThen(function (w) { - if (!password && sessionStorage.newPadPassword) { + if (!password && !stored && sessionStorage.newPadPassword) { password = sessionStorage.newPadPassword; delete sessionStorage.newPadPassword; } From a511fccdc2c8be9bc691fd819b1f542486d6f1ef Mon Sep 17 00:00:00 2001 From: yflory Date: Tue, 22 Oct 2019 16:15:13 +0200 Subject: [PATCH 09/10] Don't log error when a friend's avatar has been deleted --- www/common/common-ui-elements.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index 2f7261326..6bce00d8f 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -2087,10 +2087,7 @@ define([ var cryptKey = Hash.encodeBase64(secret.keys && secret.keys.cryptKey); var src = origin + Hash.getBlobPathFromHex(hexFileName); common.getFileSize(hexFileName, function (e, data) { - if (e || !data) { - displayDefault(); - return void console.error(e || "404 avatar"); - } + if (e || !data) { return void displayDefault(); } if (typeof data !== "number") { return void displayDefault(); } if (Util.bytesToMegabytes(data) > 0.5) { return void displayDefault(); } var $img = $('').appendTo($container); From 126f10b782a8bd3a31637476d25ce95a22ecff4e Mon Sep 17 00:00:00 2001 From: yflory Date: Tue, 22 Oct 2019 17:23:31 +0200 Subject: [PATCH 10/10] Fix shared folder password change issues --- www/common/cryptpad-common.js | 4 +-- www/common/drive-ui.js | 2 +- www/common/outer/sharedfolder.js | 44 ++++++++++++++++++++------------ www/common/proxy-manager.js | 5 ++++ www/teams/inner.js | 2 +- 5 files changed, 35 insertions(+), 22 deletions(-) diff --git a/www/common/cryptpad-common.js b/www/common/cryptpad-common.js index f0def2f9c..827884db6 100644 --- a/www/common/cryptpad-common.js +++ b/www/common/cryptpad-common.js @@ -957,9 +957,7 @@ define([ href: href, oldChannel: oldChannel, password: newPassword - }, waitFor(function (obj) { - console.error(obj); - })); + }, waitFor()); return; } pad.leavePad({ diff --git a/www/common/drive-ui.js b/www/common/drive-ui.js index 072f144fa..a48f922ee 100644 --- a/www/common/drive-ui.js +++ b/www/common/drive-ui.js @@ -4481,7 +4481,7 @@ define([ onClose: cb }); }; - if (typeof (deprecated) === "object") { + if (typeof (deprecated) === "object" && APP.editable) { Object.keys(deprecated).forEach(function (fId) { var data = deprecated[fId]; var sfId = manager.user.userObject.getSFIdFromHref(data.href); diff --git a/www/common/outer/sharedfolder.js b/www/common/outer/sharedfolder.js index 1778db3f3..7816029c3 100644 --- a/www/common/outer/sharedfolder.js +++ b/www/common/outer/sharedfolder.js @@ -49,29 +49,31 @@ define([ store.manager.addProxy(id, sf.rt.proxy, leave); cb(sf.rt, sf.metadata); }); - sf.teams.push(store); + sf.teams.push({ + cb: cb, + store: store, + id: id + }); if (handler) { handler(id, sf.rt); } - return sf.rt; + return; } - if (sf && sf.queue && sf.rt) { + if (sf && !sf.ready && sf.rt) { // The shared folder is loading, add our callbacks to the queue - sf.queue.push({ + sf.teams.push({ cb: cb, store: store, id: id }); - sf.teams.push(store); if (handler) { handler(id, sf.rt); } - return sf.rt; + return; } sf = allSharedFolders[secret.channel] = { - queue: [{ + teams: [{ cb: cb, store: store, id: id }], - teams: [store] }; var owners = data.owners; @@ -92,25 +94,27 @@ define([ }; var rt = sf.rt = Listmap.create(listmapConfig); rt.proxy.on('ready', function (info) { - if (!sf.queue) { + if (!sf.teams) { return; } - sf.queue.forEach(function (obj) { + sf.teams.forEach(function (obj) { var leave = function () { SF.leave(secret.channel, teamId); }; obj.store.manager.addProxy(obj.id, rt.proxy, leave); obj.cb(rt, info.metadata); }); sf.metadata = info.metadata; sf.ready = true; - delete sf.queue; }); rt.proxy.on('error', function (info) { if (info && info.error) { if (info.error === "EDELETED" ) { try { // Deprecate the shared folder from each team - sf.teams.forEach(function (store) { - store.manager.deprecateProxy(id, secret.channel); + // XXX We can't deprecate a read-only proxy: the read-only seed will change... + // We can only remove it + sf.teams.forEach(function (obj) { + console.log(obj.store.id, obj.store, obj.id); + obj.store.manager.deprecateProxy(obj.id, secret.channel); }); } catch (e) {} delete allSharedFolders[secret.channel]; @@ -128,8 +132,8 @@ define([ var clients = sf.teams; if (!Array.isArray(clients)) { return; } var idx; - clients.some(function (store, i) { - if (store.id === teamId) { + clients.some(function (obj, i) { + if (obj.store.id === teamId) { idx = i; return true; } @@ -145,6 +149,7 @@ define([ } }; + // Update the password locally SF.updatePassword = function (Store, data, network, cb) { var oldChannel = data.oldChannel; var href = data.href; @@ -157,13 +162,18 @@ define([ sf.rt.stop(); } var nt = nThen; - sf.teams.forEach(function (s) { + sf.teams.forEach(function (obj) { + // XXX if we're a viewer in this team, we can't update the keys nt = nt(function (waitFor) { - var sfId = s.manager.user.userObject.getSFIdFromHref(href); + var s = obj.store; + var sfId = obj.id; var shared = Util.find(s.proxy, ['drive', UserObject.SHARED_FOLDERS]) || {}; if (!sfId || !shared[sfId]) { return; } var sf = JSON.parse(JSON.stringify(shared[sfId])); sf.password = password; + sf.channel = secret.channel; + sf.href = '/drive/#'+Hash.getEditHashFromKeys(secret); // XXX encrypt + sf.roHref = '/drive/#'+Hash.getViewHashFromKeys(secret); SF.load({ network: network, store: s, diff --git a/www/common/proxy-manager.js b/www/common/proxy-manager.js index cf7f7d78b..13515be5c 100644 --- a/www/common/proxy-manager.js +++ b/www/common/proxy-manager.js @@ -508,7 +508,12 @@ define([ if (isNew) { return void cb({ error: 'ENOTFOUND' }); } + var parsed = Hash.parsePadUrl(href); + var secret = Hash.getSecrets(parsed.type, parsed.hash, newPassword); data.password = newPassword; + data.channel = secret.channel; + data.href = '/drive/#'+Hash.getEditHashFromKeys(secret); // XXX encrypt + data.roHref = '/drive/#'+Hash.getViewHashFromKeys(secret); _addSharedFolder(Env, { path: ['root'], folderData: data, diff --git a/www/teams/inner.js b/www/teams/inner.js index 40b410954..6c42429ca 100644 --- a/www/teams/inner.js +++ b/www/teams/inner.js @@ -374,7 +374,7 @@ define([ var isOwner = Object.keys(privateData.teams || {}).filter(function (id) { return privateData.teams[id].owner; - }).length >= Constants.MAX_TEAMS_OWNED; // && !privateData.devMode; + }).length >= Constants.MAX_TEAMS_OWNED && !privateData.devMode; var getWarningBox = function () { return h('div.alert.alert-warning', {