From 56d985cb8376bf1d654c0ad80be22b155dfc2159 Mon Sep 17 00:00:00 2001 From: ClemDee Date: Fri, 21 Jun 2019 12:29:26 +0200 Subject: [PATCH 01/18] Fix markdown link in title issue --- www/common/diffMarked.js | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/www/common/diffMarked.js b/www/common/diffMarked.js index 926be24b8..ff522ead6 100644 --- a/www/common/diffMarked.js +++ b/www/common/diffMarked.js @@ -45,6 +45,7 @@ define([ var toc = []; var getTOC = function () { + console.log(toc); var content = [h('h2', Messages.markdown_toc)]; toc.forEach(function (obj) { // Only include level 2 headings @@ -84,7 +85,14 @@ define([ } }; + var stripTags = function (text) { + var div = document.createElement("div"); + div.innerHTML = text; + return div.innerText; + } + renderer.heading = function (text, level) { + console.log(text, level); var i = 0; var safeText = text.toLowerCase().replace(/[^\w]+/g, '-'); var getId = function () { @@ -99,7 +107,7 @@ define([ toc.push({ level: level, id: id, - title: text + title: stripTags(text) }); return "" + text + ""; }; @@ -122,10 +130,10 @@ define([ } if (!isCheckedTaskItem && !isUncheckedTaskItem && hasBogusInput) { if (/checked/.test(text)) { - text = text.replace(bogusCheckPtn, + text = text.replace(bogusCheckPtn, '') + '\n'; } else if (/disabled/.test(text)) { - text = text.replace(bogusCheckPtn, + text = text.replace(bogusCheckPtn, '') + '\n'; } } From 0d3f8ab9e7d734a0225b60f6d2149df3198fc0ee Mon Sep 17 00:00:00 2001 From: ansuz Date: Fri, 21 Jun 2019 15:48:56 +0200 Subject: [PATCH 02/18] update CHANGELOG for Yak release (2.24.0) --- CHANGELOG.md | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d227edc7d..2abf99b75 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,79 @@ +# Yak release (v2.24.0) + +## Goals + +We've recently had an intern join our team, so this release and those until the end of summer are likely to feature a lot of small usability fixes. +Otherwise, we've continued to develop team-centric features, particularly the way that registered users share pads with friends. +Finally, we prioritized the ability to archive files for a period instead of deleting them, which we've been planning for a while. + +## Update notes + +* There are some important steps in this release: + * **make sure you read the full update notes before proceeding!** +* [@zimbatm](https://github.com/zimbatm) added the ability to configure the location of your configuration file via environment variables when launching the server: + * `CRYPTPAD_CONFIG=/home/cryptpad/cryptpad/cryptpad-config/config.js /home/cryptpad/cryptpad/server.js` +* We discovered a bug in our Xenops release which resulted in the server's list of pads stored for each user to be incorrect. + * if you're running CryptPad 2.23.0, we recommend that you disable any scripts configured to delete inactive pads + * updating to 2.24.0 will fix the issue in the client, but each user's list of "pinned pads" won't be corrected until they visit your instance and run the latest code +* This release introduces the ability to archive some data instead of deleting it, since it can be scary to remove user data when you can't easily inspect it to see what it is + * to take advantage of this new functionality you'll need to update your configuration file with three new configuration points: + * set `retainData` to `true` if you want to archive channels instead of deleting them + * either by user command or due to inactivity + * the server will fall back to its default deletion behaviour if this value is `false` or not set at all + * set `archiveRetentionTime` to the number of days that an archived pad should be stored in the archive directory before being deleted permanently + * set `archivePath` to the path where you'd like archives to be stored + * it should not be publicly accessible in order to respect the users' wishes +* We've introduced some new scripts to work with the database, some of which were needed to diagnose problems stemming from the pinning bug + * `evict-inactive.js` identifies channels which are unpinned and inactive and archives them + * unlike `delete-inactive.js` it only handles channels, not files or any other kind of data + * ...but it's much safer, since nothing is removed permanently + * in the coming releases we'll implement archival for other types of data so that we can fully remove unsafe scripts + * `diagnose-archive-conflicts.js` checks all the files in your archive and identifies whether they can be restored safely or if they conflict with newer files in the production database + * `restore-archived.js` restores any channels archived by the server or evict-inactive.js, excluding those which would conflict with the database +* This release depends on updates to some serverside dependencies. Run `npm update`: + * `ws` addresses a potential vulnerability, so if possible anyone running earlier versions of CryptPad should update + * `chainpad-server` handles users' websocket connections and we needed to make a few changes to deal with changes in the `ws` API + * `heapdump` is no longer a default dependency, though you can install it if you want its functionality +* This release also features a **Clientside migration** which modifies users' CryptDrives. Any clients which are running both the latest code after the update as well as an older version in another browser or device risk creating conflicts in their account data. To prevent this, update in the following manner: + 1. ensure that you've added the configuration values listed above + 2. shut down the server and ensure that it doesn't restart until you've completed the following steps + 3. pull the latest clientside and serverside code via git + 4. `npm update` to get the latest serverside dependencies + 5. update the cache-busting string if you are handling the cache manually, otherwise allow the server to handle this as per its default + 5. restart the server: clients with open tabs should be prompted to reload instead of reconnecting because the server's version has changed +* We recommend that you test a local version of CryptPad before deploying this latest code, as aspects of the above-mentioned migrations are not backwards-compatible. + * you can roll back, but users' CryptDrives might have errors coping with data introduced by newer features. + +## Features + +* As mentioned above, CryptPad instances can be configured to temporarily archive files instead of deleting them permanently. + * as a user this means if you accidentally delete a file you have the option of contacting your administrator and asking them to help + * if they're really nice and have the spare time to help you, they might actually recover your data! +* A contributor is working on translating CryptPad into the Catalan language. + * if your preferred language isn't supported, you can do the same on https://weblate.cryptpad.fr +* We added the ability to add colors to folders in users CryptDrives, along with support for arbitrary folder metadata which we aren't using yet. +* Users with existing friends on the platform will run a migration to allow them to share pads with friends directly instead of sending them a link. + * they'll receive a notification indicating the title of the pad and who shared it + * if you've already added friends on the platform, you can send them pads from the usual "sharing menu" +* Our code editor already offered the ability to set their color theme and highlighting mode, but now those values will be previewed when mousing over the the option in the dropdown. + * Our slide editor now offers the same theme selection as the code editor +* It's now possible to view the history of a shared folder by clicking the history button while viewing the shared folder's contents. + +## Bug fixes + +* The CryptDrive received a number of usability fixes this time around: + * better styles when hovering over interactive elements in the drive (cursors, shading, etc) + * clicking the history button in the drive a second time will exit history mode + * after being resized, the tree pane now correctly responds to mobile layout styles + * the path indicator also adapts to very narrow layouts + * the user's current location is preserved when renaming the current folder or its ancestors + * you can right-click on elements in the tree and expand or collapse all of their children +* A user noticed that one-on-one chats did not seem to be deleted, as their messages were still available after a reload. + * they were deleted but our usage of the sharedWorker API incorrectly preserved a local cache of those message until you closed all of your browser tabs +* We've also fixed some elements of the chat UI, notably the position of the chat's scrollbar when first loading older messages and how the interface scrolls to keep up with new messages. +* We've noticed some cases of tooltips getting stuck in the UI and implemented some measures to prevent this from happening. +* After "unfriending" another user it was possible that they would be automatically re-added as friends. + # Xenops release (v2.23.0) ## Goals From 8545ed749aeda15f8fa4156c9e7a5ee39ef02d85 Mon Sep 17 00:00:00 2001 From: ClemDee Date: Fri, 21 Jun 2019 17:29:15 +0200 Subject: [PATCH 03/18] Fix missing semicolon --- www/common/diffMarked.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/common/diffMarked.js b/www/common/diffMarked.js index ff522ead6..5861746c3 100644 --- a/www/common/diffMarked.js +++ b/www/common/diffMarked.js @@ -89,7 +89,7 @@ define([ var div = document.createElement("div"); div.innerHTML = text; return div.innerText; - } + }; renderer.heading = function (text, level) { console.log(text, level); From 8fb66daf7baab15de4d8ccf5e879d42087172e32 Mon Sep 17 00:00:00 2001 From: ClemDee Date: Mon, 24 Jun 2019 10:58:32 +0200 Subject: [PATCH 04/18] preview theme in pads with arrow keys in dropdown --- www/common/common-ui-elements.js | 7 ++++++- www/common/sframe-common-codemirror.js | 4 ++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index c6668e41f..70da31523 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -1737,16 +1737,20 @@ define([ var pressed = ''; var to; $container.keydown(function (e) { - var $value = $innerblock.find('[data-value].cp-dropdown-element-active'); + var $value = $innerblock.find('[data-value].cp-dropdown-element-active:visible'); if (e.which === 38) { // Up if ($value.length) { + $value.mouseleave(); var $prev = $value.prev(); + $prev.mouseenter(); setActive($prev); } } if (e.which === 40) { // Down if ($value.length) { + $value.mouseleave(); var $next = $value.next(); + $next.mouseenter(); setActive($next); } } @@ -1757,6 +1761,7 @@ define([ } } if (e.which === 27) { // Esc + $value.mouseleave(); hide(); } }); diff --git a/www/common/sframe-common-codemirror.js b/www/common/sframe-common-codemirror.js index 3636e5b6c..ebf7d752e 100644 --- a/www/common/sframe-common-codemirror.js +++ b/www/common/sframe-common-codemirror.js @@ -231,7 +231,7 @@ define([ }; var $block = exp.$language = UIElements.createDropdown(dropdownConfig); $block.find('button').attr('title', Messages.languageButtonTitle); - + var isHovering = false; var $aLanguages = $block.find('a'); $aLanguages.mouseenter(function () { @@ -304,7 +304,7 @@ define([ setTheme(theme, $block); Common.setAttribute(themeKey, theme); }); - + if ($drawer) { $drawer.append($block); } if (cb) { cb(); } }; From f5858f524d1c40e362dc791b64731cbff849c84a Mon Sep 17 00:00:00 2001 From: yflory Date: Mon, 24 Jun 2019 12:17:08 +0200 Subject: [PATCH 05/18] Fix invalid file ID in the drive --- www/common/outer/userObject.js | 5 +++++ www/common/proxy-manager.js | 1 + www/common/userObject.js | 4 ++-- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/www/common/outer/userObject.js b/www/common/outer/userObject.js index e67dd5f01..1f8b73da9 100644 --- a/www/common/outer/userObject.js +++ b/www/common/outer/userObject.js @@ -626,6 +626,11 @@ define([ var toClean = []; for (var id in fd) { id = Number(id); + if (!id && id !== 0) { + debug("Invalid file ID in filesData.", id); + toClean.push(id); + continue; + } var el = fd[id]; // Clean corrupted data diff --git a/www/common/proxy-manager.js b/www/common/proxy-manager.js index 017a403bb..8bbf641f6 100644 --- a/www/common/proxy-manager.js +++ b/www/common/proxy-manager.js @@ -729,6 +729,7 @@ define([ if (type === "pin") { return function (fileId) { var data = userObject.getFileData(fileId); + if (!data) { return; } // Don't pin pads owned by someone else if (_ownedByOther(Env, data.owners)) { return; } // Don't push duplicates diff --git a/www/common/userObject.js b/www/common/userObject.js index a9068afe6..f39e80aee 100644 --- a/www/common/userObject.js +++ b/www/common/userObject.js @@ -311,12 +311,12 @@ define([ _getFiles[FILES_DATA] = function () { var ret = []; if (!files[FILES_DATA]) { return ret; } - return Object.keys(files[FILES_DATA]).map(Number); + return Object.keys(files[FILES_DATA]).map(Number).filter(Boolean); }; _getFiles[SHARED_FOLDERS] = function () { var ret = []; if (!files[SHARED_FOLDERS]) { return ret; } - return Object.keys(files[SHARED_FOLDERS]).map(Number); + return Object.keys(files[SHARED_FOLDERS]).map(Number).filter(Boolean); }; var getFiles = exp.getFiles = function (categories) { var ret = []; From bba3e355d00ec3c11e062ee0c6d7c9657df58c36 Mon Sep 17 00:00:00 2001 From: yflory Date: Mon, 24 Jun 2019 12:28:46 +0200 Subject: [PATCH 06/18] Invalid ID fix --- www/common/outer/userObject.js | 4 ++-- www/common/proxy-manager.js | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/www/common/outer/userObject.js b/www/common/outer/userObject.js index 1f8b73da9..e12883eb5 100644 --- a/www/common/outer/userObject.js +++ b/www/common/outer/userObject.js @@ -625,12 +625,12 @@ define([ var root = exp.find([ROOT]); var toClean = []; for (var id in fd) { - id = Number(id); - if (!id && id !== 0) { + if (String(id) !== String(Number(id))) { debug("Invalid file ID in filesData.", id); toClean.push(id); continue; } + id = Number(id); var el = fd[id]; // Clean corrupted data diff --git a/www/common/proxy-manager.js b/www/common/proxy-manager.js index 8bbf641f6..fdfde9263 100644 --- a/www/common/proxy-manager.js +++ b/www/common/proxy-manager.js @@ -707,6 +707,7 @@ define([ if (type === 'expirable') { return function (fileId) { var data = userObject.getFileData(fileId); + if (!data) { return; } // Don't push duplicates if (result.indexOf(data.channel) !== -1) { return; } // Return pads owned by someone else or expired by time @@ -718,6 +719,7 @@ define([ if (type === 'owned') { return function (fileId) { var data = userObject.getFileData(fileId); + if (!data) { return; } // Don't push duplicates if (result.indexOf(data.channel) !== -1) { return; } // Return owned pads From d16aa7de8a7c6b0210ebb5af80e29b369d3fc623 Mon Sep 17 00:00:00 2001 From: ClemDee <45625842+ClemDee@users.noreply.github.com> Date: Mon, 24 Jun 2019 15:00:44 +0200 Subject: [PATCH 07/18] Remove console.logs --- www/common/diffMarked.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/www/common/diffMarked.js b/www/common/diffMarked.js index 5861746c3..35633c4cd 100644 --- a/www/common/diffMarked.js +++ b/www/common/diffMarked.js @@ -45,7 +45,6 @@ define([ var toc = []; var getTOC = function () { - console.log(toc); var content = [h('h2', Messages.markdown_toc)]; toc.forEach(function (obj) { // Only include level 2 headings @@ -92,7 +91,6 @@ define([ }; renderer.heading = function (text, level) { - console.log(text, level); var i = 0; var safeText = text.toLowerCase().replace(/[^\w]+/g, '-'); var getId = function () { From 905bbef8238017ace07af812cfa50c6803e54158 Mon Sep 17 00:00:00 2001 From: yflory Date: Mon, 24 Jun 2019 18:15:53 +0200 Subject: [PATCH 08/18] Add FIXME comments --- www/common/common-ui-elements.js | 2 +- www/common/proxy-manager.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index c6668e41f..24e50863f 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -162,7 +162,7 @@ define([ } var parsed = Hash.parsePadUrl(data.href || data.roHref); - if (!data.noEditPassword && owned && parsed.hashData.type === 'pad') { + if (!data.noEditPassword && owned && parsed.hashData.type === 'pad' && parsed.type !== "sheet") { // FIXME SHEET fix password change for sheets var sframeChan = common.getSframeChannel(); var changePwTitle = Messages.properties_changePassword; var changePwConfirm = Messages.properties_confirmChange; diff --git a/www/common/proxy-manager.js b/www/common/proxy-manager.js index fdfde9263..9d8bbe6ba 100644 --- a/www/common/proxy-manager.js +++ b/www/common/proxy-manager.js @@ -342,7 +342,7 @@ define([ }); // Remove the elements from the old location (without unpinning) - Env.user.userObject.delete(resolved.main, waitFor()); + Env.user.userObject.delete(resolved.main, waitFor()); // FIXME waitFor() is called synchronously } } } @@ -369,7 +369,7 @@ define([ if (copy) { return; } // Remove the elements from the old location (without unpinning) - uoFrom.delete(paths, waitFor()); + uoFrom.delete(paths, waitFor()); // FIXME waitFor() is called synchronously } }); } From 59d5723f3e7e7d61d3643205b821007b2f471848 Mon Sep 17 00:00:00 2001 From: yflory Date: Mon, 24 Jun 2019 18:16:32 +0200 Subject: [PATCH 09/18] Fix read-only spreadsheets --- www/common/onlyoffice/main.js | 7 +++++-- www/common/outer/onlyoffice.js | 29 +++++++++++++++++++++++------ 2 files changed, 28 insertions(+), 8 deletions(-) diff --git a/www/common/onlyoffice/main.js b/www/common/onlyoffice/main.js index d056cad42..6bd6c7df5 100644 --- a/www/common/onlyoffice/main.js +++ b/www/common/onlyoffice/main.js @@ -102,9 +102,12 @@ define([ Cryptpad.onlyoffice.onEvent.reg(function (obj) { if (obj.ev === 'MESSAGE' && !/^cp\|/.test(obj.data)) { try { + var validateKey = obj.data.validateKey || true; + var skipCheck = validateKey === true; + var msg = obj.data.msg; obj.data = { - msg: JSON.parse(Utils.crypto.decrypt(obj.data, Utils.secret.keys.validateKey)), - hash: obj.data.slice(0,64) + msg: JSON.parse(Utils.crypto.decrypt(msg, validateKey, skipCheck)), + hash: msg.slice(0,64) }; } catch (e) { console.error(e); diff --git a/www/common/outer/onlyoffice.js b/www/common/outer/onlyoffice.js index 3b57b4123..70bc413ec 100644 --- a/www/common/outer/onlyoffice.js +++ b/www/common/outer/onlyoffice.js @@ -26,7 +26,10 @@ define([ if (!c.id) { c.id = chan.wc.myID + '-' + client; } chan.history.forEach(function (msg) { - ctx.emit('MESSAGE', msg, [client]); + ctx.emit('MESSAGE', { + msg: msg, + validateKey: chan.validateKey + }, [client]); }); // ==> And push the new tab to the list @@ -37,7 +40,8 @@ define([ var onOpen = function (wc) { ctx.channels[channel] = ctx.channels[channel] || { - history: [] + history: [], + validateKey: obj.validateKey }; chan = ctx.channels[channel]; @@ -61,7 +65,10 @@ define([ }); wc.on('message', function (msg) { chan.history.push(msg); - ctx.emit('MESSAGE', msg, chan.clients); + ctx.emit('MESSAGE', { + msg: msg, + validateKey: chan.validateKey + }, chan.clients); }); chan.wc = wc; @@ -101,6 +108,7 @@ define([ }; network.on('message', function (msg, sender) { + if (!ctx.channels[channel]) { return; } var hk = network.historyKeeper; if (sender !== hk) { return; } @@ -115,7 +123,12 @@ define([ // Keep only metadata messages for the current channel if (parsed.channel && parsed.channel !== channel) { return; } // Ignore the metadata message - if (parsed.validateKey && parsed.channel) { return; } + if (parsed.validateKey && parsed.channel) { + if (!chan.validateKey) { + chan.validateKey = parsed.validateKey; + } + return; + } // End of history: emit READY if (parsed.state && parsed.state === 1 && parsed.channel) { ctx.emit('READY', '', chan.clients); @@ -132,7 +145,9 @@ define([ if (hash === chan.lastKnownHash || hash === chan.lastCpHash) { return; } chan.lastKnownHash = hash; - ctx.emit('MESSAGE', msg, chan.clients); + ctx.emit('MESSAGE', { + msg: msg, + }, chan.clients); chan.history.push(msg); }); @@ -176,7 +191,9 @@ define([ return void chan.sendMsg(data.isCp, cb); } chan.sendMsg(data.msg, cb); - ctx.emit('MESSAGE', data.msg, chan.clients.filter(function (cl) { + ctx.emit('MESSAGE', { + msg: data.msg + }, chan.clients.filter(function (cl) { return cl !== clientId; })); }; From 4b8a8fbe5fd91230880da146c67c0eabe97b369f Mon Sep 17 00:00:00 2001 From: ansuz Date: Tue, 25 Jun 2019 11:13:03 +0200 Subject: [PATCH 10/18] add mkAsync function --- www/assert/main.js | 17 ++++++++++++++++- www/common/common-util.js | 9 +++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/www/assert/main.js b/www/assert/main.js index 17769868d..ec69f4d5e 100644 --- a/www/assert/main.js +++ b/www/assert/main.js @@ -11,9 +11,10 @@ define([ '/common/flat-dom.js', '/common/media-tag.js', '/common/outer/login-block.js', + '/common/common-util.js', '/bower_components/tweetnacl/nacl-fast.min.js', -], function ($, Hyperjson, Sortify, Drive, Test, Hash, Util, Thumb, Wire, Flat, MediaTag, Block) { +], function ($, Hyperjson, Sortify, Drive, Test, Hash, Util, Thumb, Wire, Flat, MediaTag, Block, Util) { window.Hyperjson = Hyperjson; window.Sortify = Sortify; var Nacl = window.nacl; @@ -371,6 +372,20 @@ define([ return cb(true); }, "version 2 hash failed to parse correctly"); + assert(function (cb) { + var x; + var set_x = function (v) { + x = v; + }; + + Util.mkAsync(set_x)(7); + set_x(5); + + Util.mkAsync(function (expected) { + cb(x === expected); + })(7); + }, "test mkAsync"); + assert(function (cb) { Wire.create({ constructor: function (cb) { diff --git a/www/common/common-util.js b/www/common/common-util.js index 7afbf7c27..9fd2305c3 100644 --- a/www/common/common-util.js +++ b/www/common/common-util.js @@ -2,6 +2,15 @@ define([], function () { var Util = window.CryptPad_Util = {}; + Util.mkAsync = function (f) { + return function () { + var args = Array.prototype.slice.call(arguments); + setTimeout(function () { + f.apply(null, args); + }); + }; + }; + // If once is true, after the event has been fired, any further handlers which are // registered will fire immediately, and this type of event cannot be fired twice. Util.mkEvent = function (once) { From 60673103ad9ee90006b81a77d7aeeccc3aaed49b Mon Sep 17 00:00:00 2001 From: ansuz Date: Tue, 25 Jun 2019 11:25:44 +0200 Subject: [PATCH 11/18] don't require the same thing twice --- www/assert/main.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/www/assert/main.js b/www/assert/main.js index ec69f4d5e..6ad05a7a2 100644 --- a/www/assert/main.js +++ b/www/assert/main.js @@ -11,10 +11,9 @@ define([ '/common/flat-dom.js', '/common/media-tag.js', '/common/outer/login-block.js', - '/common/common-util.js', '/bower_components/tweetnacl/nacl-fast.min.js', -], function ($, Hyperjson, Sortify, Drive, Test, Hash, Util, Thumb, Wire, Flat, MediaTag, Block, Util) { +], function ($, Hyperjson, Sortify, Drive, Test, Hash, Util, Thumb, Wire, Flat, MediaTag, Block) { window.Hyperjson = Hyperjson; window.Sortify = Sortify; var Nacl = window.nacl; From 2d881caaeba7ef602f6ff504acd4563d1123b989 Mon Sep 17 00:00:00 2001 From: yflory Date: Tue, 25 Jun 2019 15:07:43 +0200 Subject: [PATCH 12/18] Fix accounts href in limit popup --- www/common/toolbar3.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/www/common/toolbar3.js b/www/common/toolbar3.js index 303a983e0..2da2fc7d8 100644 --- a/www/common/toolbar3.js +++ b/www/common/toolbar3.js @@ -832,11 +832,17 @@ MessengerUI, Messages) { return $spin; }; - var createLimit = function (toolbar) { + var createLimit = function (toolbar, config) { var $limitIcon = $('', {'class': 'fa fa-exclamation-triangle'}); var $limit = toolbar.$userAdmin.find('.'+LIMIT_CLS).attr({ 'title': Messages.pinLimitReached }).append($limitIcon).hide(); + + var priv = config.metadataMgr.getPrivateData(); + var origin = priv.origin; + var l = document.createElement("a"); + l.href = origin; + var todo = function (e, overLimit) { if (e) { return void console.error("Unable to get the pinned usage", e); } if (overLimit) { @@ -845,7 +851,7 @@ MessengerUI, Messages) { key = 'pinLimitReachedAlertNoAccounts'; } $limit.show().click(function () { - UI.alert(Messages._getKey(key, [encodeURIComponent(window.location.hostname)]), null, true); + UI.alert(Messages._getKey(key, [encodeURIComponent(l.hostname)]), null, true); }); } }; From 9aebeb216e32f4830c31b3cfb00bfbc4a57fe21c Mon Sep 17 00:00:00 2001 From: yflory Date: Mon, 1 Jul 2019 18:06:16 +0200 Subject: [PATCH 13/18] Add the password when sharing a pad with a friend --- www/common/common-ui-elements.js | 1 + www/drive/inner.js | 3 +++ www/share/inner.js | 1 + 3 files changed, 5 insertions(+) diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index 3149e4e5d..abe9c7938 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -412,6 +412,7 @@ define([ if (!friend.notifications || !friend.curvePublic) { return; } common.mailbox.sendTo("SHARE_PAD", { href: href, + password: config.password, name: myName, title: title }, { diff --git a/www/drive/inner.js b/www/drive/inner.js index 596465396..c2c0332a4 100644 --- a/www/drive/inner.js +++ b/www/drive/inner.js @@ -2173,6 +2173,7 @@ define([ pathname: "/drive/", friends: friends, title: data.title, + password: data.password, common: common, hashes: { editHash: parsed.hash @@ -3510,6 +3511,7 @@ define([ friends: friends, title: data.title, common: common, + password: data.password, hashes: { editHash: parsed.hash } @@ -3523,6 +3525,7 @@ define([ origin: APP.origin, pathname: "/" + padType + "/", friends: friends, + password: data.password, hashes: { editHash: parsed.hash, viewHash: roParsed.hash, diff --git a/www/share/inner.js b/www/share/inner.js index fbc1f48cc..d50bb9a9c 100644 --- a/www/share/inner.js +++ b/www/share/inner.js @@ -42,6 +42,7 @@ define([ var modal = f({ origin: origin, pathname: pathname, + password: priv.password, hashes: hashes, common: common, title: data.title, From 7a0f30488cea5c03c7217ee26ac9c796c5ceadc0 Mon Sep 17 00:00:00 2001 From: yflory Date: Mon, 1 Jul 2019 18:07:40 +0200 Subject: [PATCH 14/18] Hide duplicates when receiving access to a pad via notifications --- www/common/outer/mailbox-handlers.js | 47 +++++++++++++++++++++++++++- www/common/outer/mailbox.js | 10 ++++-- 2 files changed, 54 insertions(+), 3 deletions(-) diff --git a/www/common/outer/mailbox-handlers.js b/www/common/outer/mailbox-handlers.js index 0ab804dcf..befd0d11f 100644 --- a/www/common/outer/mailbox-handlers.js +++ b/www/common/outer/mailbox-handlers.js @@ -1,6 +1,7 @@ define([ '/common/common-messaging.js', -], function (Messaging) { + '/common/common-hash.js', +], function (Messaging, Hash) { var getRandomTimeout = function (ctx) { var lag = ctx.store.realtime.getLag().lag || 0; @@ -156,6 +157,50 @@ define([ cb(true); }; + // Hide duplicates when receiving a SHARE_PAD notification: + // Keep only one notification per channel: the stronger and more recent one + var channels = {}; + handlers['SHARE_PAD'] = function (ctx, box, data, cb) { + var msg = data.msg; + var hash = data.hash; + var content = msg.content; + // content.name, content.title, content.href, content.password + + var channel = Hash.hrefToHexChannelId(content.href, content.password); + var parsed = Hash.parsePadUrl(content.href); + var mode = parsed.hashData && parsed.hashData.mode || 'n/a'; + + var old = channels[channel]; + var toRemove; + if (old) { + // New hash is weaker, ignore + if (old.mode === 'edit' && mode === 'view') { + return void cb(true); + } + // New hash is not weaker, clear the old one + toRemove = old.data; + } + + // Update the data + channels[channel] = { + mode: mode, + data: { + type: box.type, + hash: hash + } + } + + cb(false, toRemove); + }; + removeHandlers['SHARE_PAD'] = function (ctx, box, data, hash) { + var content = data.content; + var channel = Hash.hrefToHexChannelId(content.href, content.password); + var old = channels[channel]; + if (old && old.data && old.data.hash === hash) { + delete channels[channel]; + } + }; + return { add: function (ctx, box, data, cb) { /** diff --git a/www/common/outer/mailbox.js b/www/common/outer/mailbox.js index 550573411..90d536bc3 100644 --- a/www/common/outer/mailbox.js +++ b/www/common/outer/mailbox.js @@ -157,6 +157,7 @@ proxy.mailboxes = { var openChannel = function (ctx, type, m, onReady) { var box = ctx.boxes[type] = { + type: type, queue: [], // Store the messages to send when the channel is ready history: [], // All the hashes loaded from the server in corretc order content: {}, // Content of the messages that should be displayed @@ -228,8 +229,8 @@ proxy.mailboxes = { msg: msg, hash: hash }; - Handlers.add(ctx, box, message, function (toDismiss) { - if (toDismiss) { + Handlers.add(ctx, box, message, function (dismissed, toDismiss) { + if (dismissed) { // This message should be removed dismiss(ctx, { type: type, hash: hash @@ -238,6 +239,11 @@ proxy.mailboxes = { }); return; } + if (toDismiss) { // List of other messages to remove + dismiss(ctx, toDismiss, '', function () { + console.log('Notification handled automatically'); + }); + } box.content[hash] = msg; showMessage(ctx, type, message); }); From 520655856b4b434755ce816f897f2f898d5bbc64 Mon Sep 17 00:00:00 2001 From: yflory Date: Mon, 1 Jul 2019 18:19:38 +0200 Subject: [PATCH 15/18] Don't ask for password when receiving a pad from the notifications --- www/common/notifications.js | 7 ++++++- www/common/sframe-common-outer.js | 5 +++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/www/common/notifications.js b/www/common/notifications.js index 136117c6f..1d7f2921c 100644 --- a/www/common/notifications.js +++ b/www/common/notifications.js @@ -57,7 +57,12 @@ define([ .html(Messages._getKey(key, [msg.content.name || Messages.anonymous, msg.content.title])); $(el).find('.cp-notification-content').addClass("cp-clickable") .click(function () { - common.openURL(msg.content.href); + var todo = function () { common.openURL(msg.content.href); }; + if (!msg.content.password) { return void todo(); } + common.getSframeChannel().query('Q_SESSIONSTORAGE_PUT', { + key: 'newPadPassword', + value: msg.content.password + }, todo); }); $(el).find('.cp-notification-dismiss').css('display', 'flex'); }; diff --git a/www/common/sframe-common-outer.js b/www/common/sframe-common-outer.js index 838f415e4..fba08279a 100644 --- a/www/common/sframe-common-outer.js +++ b/www/common/sframe-common-outer.js @@ -223,6 +223,11 @@ define([ sframeChan.event("EV_PAD_PASSWORD"); }; + if (!val && sessionStorage.newPadPassword) { + val = sessionStorage.newPadPassword; + delete sessionStorage.newPadPassword; + } + if (val) { password = val; Cryptpad.getFileSize(window.location.href, password, waitFor(function (e, size) { From 3f500cfd5ca6957d193b2ee2ed65edef36b29672 Mon Sep 17 00:00:00 2001 From: yflory Date: Mon, 1 Jul 2019 18:19:54 +0200 Subject: [PATCH 16/18] lint compliance --- www/common/outer/mailbox-handlers.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/common/outer/mailbox-handlers.js b/www/common/outer/mailbox-handlers.js index befd0d11f..10e61fb60 100644 --- a/www/common/outer/mailbox-handlers.js +++ b/www/common/outer/mailbox-handlers.js @@ -188,7 +188,7 @@ define([ type: box.type, hash: hash } - } + }; cb(false, toRemove); }; From eead5dab7a3ec48c748833b3e2d742d391604650 Mon Sep 17 00:00:00 2001 From: Weblate Date: Tue, 2 Jul 2019 12:44:06 +0000 Subject: [PATCH 17/18] Translated using Weblate (English) Currently translated at 100.0% (1009 of 1009 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 100.0% (1008 of 1008 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 100.0% (1007 of 1007 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 100.0% (1006 of 1006 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 100.0% (1006 of 1006 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 100.0% (1005 of 1005 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 100.0% (1004 of 1004 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 100.0% (1003 of 1003 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 100.0% (1002 of 1002 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 100.0% (1001 of 1001 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 100.0% (1000 of 1000 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 100.0% (1000 of 1000 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 100.0% (999 of 999 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 100.0% (999 of 999 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 100.0% (998 of 998 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 100.0% (997 of 997 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 100.0% (996 of 996 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 100.0% (995 of 995 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 100.0% (994 of 994 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 100.0% (993 of 993 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 100.0% (992 of 992 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 100.0% (991 of 991 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 100.0% (990 of 990 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 100.0% (989 of 989 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 100.0% (988 of 988 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 100.0% (987 of 987 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 100.0% (986 of 986 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 100.0% (985 of 985 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 100.0% (984 of 984 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 100.0% (983 of 983 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 100.0% (982 of 982 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ --- www/common/translations/messages.json | 30 ++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/www/common/translations/messages.json b/www/common/translations/messages.json index 027e75743..e0885452f 100644 --- a/www/common/translations/messages.json +++ b/www/common/translations/messages.json @@ -1075,5 +1075,33 @@ "share_withFriends": "Share", "notifications_dismiss": "Dismiss", "fm_info_sharedFolderHistory": "This is only the history of your shared folder: {0}
Your CryptDrive will stay in read-only mode while you navigate.", - "share_description": "Choose what you'd like to share and either get the link or send it directly to your CryptPad friends." + "share_description": "Choose what you'd like to share and either get the link or send it directly to your CryptPad friends.", + "supportPage": "Support", + "admin_cat_support": "Support", + "admin_supportInitHelp": "Your server is not yet configured to have a support mailbox. If you want a support mailbox to receive messages from your users, you should ask your server administrator to run the script located in \"./scripts/generate-admin-keys.js\", then store the public key in the \"config.js\" file and send you the private key.", + "admin_supportInitPrivate": "Your CryptPad instance is configured to use a support mailbox but your account doesn't have the correct private key to access it. Please use the following form to add or update the private key to your account.", + "admin_supportAddKey": "Add private key", + "admin_supportAddError": "Invalid private key", + "admin_supportInitTitle": "Support mailbox initialization", + "admin_supportInitHint": "You can configure a support mailbox in order to give users of your CryptPad instance a way to contact you securely if they have an issue with their account.", + "admin_supportListTitle": "Support mailbox", + "admin_supportListHint": "Here is the list of tickets sent by the users to the support mailbox. All the administrators can see the messages and the answers. A closed ticket cannot be reopened. You can only remove (hide) closed tickets, and the removed tickets are still visible by the other administrators.", + "support_disabledTitle": "Support is not enabled", + "support_disabledHint": "This CryptPad instance is not yet configured to use a support form.", + "support_cat_new": "New ticket", + "support_formTitle": "Ticket title", + "support_formHint": "This form can be used to create a new support ticket. Using this form, you can contact the administrators to solve issues or ask any question in a secure way. Please don't create a new ticket if you already have an open ticket about the same issue, but use reply button to provide more information.", + "support_formButton": "Send", + "support_formTitleError": "Error: title is empty", + "support_formContentError": "Error: content is empty", + "support_formMessage": "Type your message...", + "support_cat_tickets": "Existing tickets", + "support_listTitle": "Support tickets", + "support_listHint": "Here is the list of tickets sent to the administrators and their answers. A closed ticket cannot be re-opened, you have to make a new one. You can hide tickets that have been closed but they will still be visible by the administrators.", + "support_answer": "Reply", + "support_close": "Close the ticket", + "support_remove": "Remove the ticket", + "support_showData": "Show/hide user data", + "support_from": "From: {0}", + "support_closed": "This ticket has been closed" } From 3d6a09d3c4f7ae3a484a4e9b21b03f44c7e6303a Mon Sep 17 00:00:00 2001 From: Weblate Date: Tue, 2 Jul 2019 12:44:07 +0000 Subject: [PATCH 18/18] Translated using Weblate (German) Currently translated at 100.0% (981 of 981 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/de/ --- www/common/translations/messages.de.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/www/common/translations/messages.de.json b/www/common/translations/messages.de.json index f8618fdb9..6125abf5c 100644 --- a/www/common/translations/messages.de.json +++ b/www/common/translations/messages.de.json @@ -565,7 +565,7 @@ "download_step1": "Laden...", "download_step2": "Entschlüsselung...", "todo_title": "CryptTodo", - "todo_newTodoNamePlaceholder": "Beschreibe deine Aufgabe...", + "todo_newTodoNamePlaceholder": "Beschreibe deine Aufgabe…", "todo_newTodoNameTitle": "Diese Aufgabe zu deiner ToDo-Liste hinzufügen", "todo_markAsCompleteTitle": "Diese Aufgabe als erledigt markieren", "todo_markAsIncompleteTitle": "Diese Aufgabe als nicht erledigt markieren", @@ -830,7 +830,7 @@ "generic": { "more": "Erfahre mehr über die Nutzung von CryptPad, indem du unsere FAQ liest", "share": "Benutze das Teilen-Menü (), um Links zu generieren, die Mitarbeiter zum Lesen oder Bearbeiten einladen", - "save": "Alle Änderungen werden automatisch synchronisiert. Du misst sie also nicht speichern" + "save": "Alle Änderungen werden automatisch synchronisiert. Du musst sie also nicht selbst speichern" }, "text": { "formatting": "Du kannst die Werkzeugleiste anzeigen oder verbergen, indem du auf oder klickst",