From 5f9de6948c46f76f5e01a4040094bc77bcf3a345 Mon Sep 17 00:00:00 2001 From: muxator Date: Fri, 17 Aug 2018 22:22:14 +0200 Subject: [PATCH 001/150] cleanRun.sh: get rid of "Bad substitution" error It was introduced in 4a18f0d97d96 (#3356). --- bin/cleanRun.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/cleanRun.sh b/bin/cleanRun.sh index 57325dd23..288f5a040 100755 --- a/bin/cleanRun.sh +++ b/bin/cleanRun.sh @@ -38,4 +38,4 @@ bin/installDeps.sh $* || exit 1 echo "Started Etherpad..." SCRIPTPATH=`pwd -P` -node "${$SCRIPTPATH}/node_modules/ep_etherpad-lite/node/server.js" $* +node "${SCRIPTPATH}/node_modules/ep_etherpad-lite/node/server.js" $* From 93641a165d13f650d0b7f84bd0344fc1faf13a58 Mon Sep 17 00:00:00 2001 From: muxator Date: Sat, 18 Aug 2018 19:42:42 +0200 Subject: [PATCH 002/150] dependencies: update socket.io 1.7.3 -> 2.1.1 Version 2.x is not backwards compatible with 1.x. However, according to [0], [1] and [2], it seems that the biggest concern is when mixing different server and client versions, and this is not Etherpad's case. Smoke tested (successfully) on Firefox 61, Chromium 68. npm audit before this change: found 12 vulnerabilities (9 low, 3 high) in 8205 scanned packages 11 vulnerabilities require semver-major dependency updates. 1 vulnerability requires manual review. See the full report for details. npm audit after this change: found 1 low severity vulnerability in 8196 scanned packages 1 vulnerability requires manual review. See the full report for details. Fixes #3462 [0] https://socket.io/blog/socket-io-2-0-0/ [1] https://github.com/socketio/socket.io/issues/3007#issuecomment-336791836 [2] https://github.com/Enalean/tuleap/commit/a0d7a794ded03a0001d2164cb25a9e26b5441a89 --- src/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/package.json b/src/package.json index fcf5b97c0..b6df2acb3 100644 --- a/src/package.json +++ b/src/package.json @@ -51,7 +51,7 @@ "security": "1.0.0", "semver": "5.1.0", "slide": "1.1.6", - "socket.io": "1.7.3", + "socket.io": "2.1.1", "swagger-node-express": "2.1.3", "tinycon": "0.0.1", "ueberdb2": "0.4.0", From cb078050222a6b0392ade34e15fb2afe0870153f Mon Sep 17 00:00:00 2001 From: muxator Date: Wed, 22 Aug 2018 00:12:53 +0200 Subject: [PATCH 003/150] NodeVersion: take responsibility for ugly code --- src/node/utils/NodeVersion.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/node/utils/NodeVersion.js b/src/node/utils/NodeVersion.js index 49c1efe85..2909d5bc9 100644 --- a/src/node/utils/NodeVersion.js +++ b/src/node/utils/NodeVersion.js @@ -3,6 +3,8 @@ */ /* + * 2018 - muxator + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at From b635371d52e2dccce01e61811eb01ed7bad652ea Mon Sep 17 00:00:00 2001 From: muxator Date: Tue, 21 Aug 2018 21:57:13 +0200 Subject: [PATCH 004/150] settings: the default dirty.db location should be var/dirty.db This is the location that is choosen by default when Etherpad starts with no settings.json file. It was different than the one contained into setting.json.template. --- src/node/utils/Settings.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/node/utils/Settings.js b/src/node/utils/Settings.js index 08ace60ca..7bbfc6d07 100644 --- a/src/node/utils/Settings.js +++ b/src/node/utils/Settings.js @@ -78,7 +78,7 @@ exports.dbType = "dirty"; /** * This setting is passed with dbType to ueberDB to set up the database */ -exports.dbSettings = { "filename" : path.join(exports.root, "dirty.db") }; +exports.dbSettings = { "filename" : path.join(exports.root, "var/dirty.db") }; /** * The default Text of a new pad From ec5573f88cd02e3e72dc6928143bf1ec97f15ba6 Mon Sep 17 00:00:00 2001 From: muxator Date: Tue, 21 Aug 2018 00:05:15 +0200 Subject: [PATCH 005/150] settings, APIHandler: generate more informative logs --- src/node/handler/APIHandler.js | 5 +++++ src/node/utils/Settings.js | 9 +++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/node/handler/APIHandler.js b/src/node/handler/APIHandler.js index 05e147058..3907df79a 100644 --- a/src/node/handler/APIHandler.js +++ b/src/node/handler/APIHandler.js @@ -22,19 +22,24 @@ var ERR = require("async-stacktrace"); var fs = require("fs"); var api = require("../db/API"); +var log4js = require('log4js'); var padManager = require("../db/PadManager"); var randomString = require("../utils/randomstring"); var argv = require('../utils/Cli').argv; +var apiHandlerLogger = log4js.getLogger('APIHandler'); + //ensure we have an apikey var apikey = null; var apikeyFilename = argv.apikey || "./APIKEY.txt"; try { apikey = fs.readFileSync(apikeyFilename,"utf8"); + apiHandlerLogger.info(`Api key file read from: "${apikeyFilename}"`); } catch(e) { + apiHandlerLogger.info(`Api key file "${apikeyFilename}" not found. Creating with random contents.`); apikey = randomString(32); fs.writeFileSync(apikeyFilename,apikey,"utf8"); } diff --git a/src/node/utils/Settings.js b/src/node/utils/Settings.js index 7bbfc6d07..4168ea825 100644 --- a/src/node/utils/Settings.js +++ b/src/node/utils/Settings.js @@ -358,15 +358,18 @@ exports.reloadSettings = function reloadSettings() { try{ //read the settings sync settingsStr = fs.readFileSync(settingsFilename).toString(); + console.info(`Settings loaded from: ${settingsFilename}`); } catch(e){ - console.warn('No settings file found. Continuing using defaults!'); + console.warn(`No settings file found in ${settingsFilename}. Continuing using defaults!`); } try{ //read the credentials sync credentialsStr = fs.readFileSync(credentialsFilename).toString(); + console.info(`Credentials file read from: ${credentialsFilename}`); } catch(e){ // Doesn't matter if no credentials file found.. + console.info(`No credentials file found in ${credentialsFilename}. Ignoring.`); } // try to parse the settings @@ -378,7 +381,7 @@ exports.reloadSettings = function reloadSettings() { settings = JSON.parse(settingsStr); } }catch(e){ - console.error('There was an error processing your settings.json file: '+e.message); + console.error(`There was an error processing your settings file from ${settingsFilename}:` + e.message); process.exit(1); } @@ -479,7 +482,9 @@ exports.reloadSettings = function reloadSettings() { var sessionkeyFilename = argv.sessionkey || "./SESSIONKEY.txt"; try { exports.sessionKey = fs.readFileSync(sessionkeyFilename,"utf8"); + console.info(`Session key loaded from: ${sessionkeyFilename}`); } catch(e) { + console.info(`Session key file "${sessionkeyFilename}" not found. Creating with random contents.`); exports.sessionKey = randomString(32); fs.writeFileSync(sessionkeyFilename,exports.sessionKey,"utf8"); } From dbf7eff1fc626c4ac7a4c564dd6ceaf9ee42d351 Mon Sep 17 00:00:00 2001 From: muxator Date: Wed, 22 Aug 2018 00:24:31 +0200 Subject: [PATCH 006/150] AbsolutePaths: module for deterministically computing relative Etherpad paths Empty for now. --- src/node/utils/AbsolutePaths.js | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 src/node/utils/AbsolutePaths.js diff --git a/src/node/utils/AbsolutePaths.js b/src/node/utils/AbsolutePaths.js new file mode 100644 index 000000000..34751304f --- /dev/null +++ b/src/node/utils/AbsolutePaths.js @@ -0,0 +1,23 @@ +/** + * Library for deterministic relative filename expansion for Etherpad. + */ + +/* + * 2018 - muxator + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS-IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +var log4js = require('log4js'); + +var absPathLogger = log4js.getLogger('AbsolutePaths'); From cbce3c1b0832b13c8ab6fae664eeb79293df5c41 Mon Sep 17 00:00:00 2001 From: muxator Date: Wed, 22 Aug 2018 00:32:46 +0200 Subject: [PATCH 007/150] AbsolutePaths: written utility function popIfEndsWith() It will be necessary in the next commit to evaluate the Etherpad base install path. --- src/node/utils/AbsolutePaths.js | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/node/utils/AbsolutePaths.js b/src/node/utils/AbsolutePaths.js index 34751304f..2736599b6 100644 --- a/src/node/utils/AbsolutePaths.js +++ b/src/node/utils/AbsolutePaths.js @@ -19,5 +19,33 @@ */ var log4js = require('log4js'); +var _ = require('underscore'); var absPathLogger = log4js.getLogger('AbsolutePaths'); + +/** + * If stringArray's last elements are exactly equal to lastDesiredElements, + * returns a copy in which those last elements are popped, or false otherwise. + * + * @param {string[]} stringArray - The input array. + * @param {string[]} lastDesiredElements - The elements to remove from the end + * of the input array. + * @return {string[]|boolean} The shortened array, or false if there was no + * overlap. + */ +var popIfEndsWith = function(stringArray, lastDesiredElements) { + if (stringArray.length <= lastDesiredElements.length) { + absPathLogger.debug(`In order to pop "${lastDesiredElements.join(path.sep)}" from "${stringArray.join(path.sep)}", it should contain at least ${lastDesiredElements.length + 1 } elements`); + + return false; + } + + const lastElementsFound = _.last(stringArray, lastDesiredElements.length); + + if (_.isEqual(lastElementsFound, lastDesiredElements)) { + return _.initial(stringArray, lastDesiredElements.length); + } + + absPathLogger.debug(`${stringArray.join(path.sep)} does not end with "${lastDesiredElements.join(path.sep)}"`); + return false; +}; From b1a0e14ee2b7c4e39c3b83591adf273df7a59417 Mon Sep 17 00:00:00 2001 From: muxator Date: Wed, 22 Aug 2018 00:38:13 +0200 Subject: [PATCH 008/150] AbsolutePaths: written findEtherpadRoot() This is just a function (with an ugly side effect for caching purposes) that heuristically tries to compute the Etherpad installation path when running under Unix and win32 (they have different file system layouts). This path can be used by Etherpad as a base for all the relative paths, in order to be deterministic and not depending on cwd. --- src/node/utils/AbsolutePaths.js | 65 +++++++++++++++++++++++++++++++++ src/package.json | 1 + 2 files changed, 66 insertions(+) diff --git a/src/node/utils/AbsolutePaths.js b/src/node/utils/AbsolutePaths.js index 2736599b6..3a7e60f0d 100644 --- a/src/node/utils/AbsolutePaths.js +++ b/src/node/utils/AbsolutePaths.js @@ -19,10 +19,17 @@ */ var log4js = require('log4js'); +var path = require('path'); var _ = require('underscore'); var absPathLogger = log4js.getLogger('AbsolutePaths'); +/* + * findEtherpadRoot() computes its value only on first invocation. + * Subsequent invocations are served from this variable. + */ +var etherpadRoot = null; + /** * If stringArray's last elements are exactly equal to lastDesiredElements, * returns a copy in which those last elements are popped, or false otherwise. @@ -49,3 +56,61 @@ var popIfEndsWith = function(stringArray, lastDesiredElements) { absPathLogger.debug(`${stringArray.join(path.sep)} does not end with "${lastDesiredElements.join(path.sep)}"`); return false; }; + +/** + * Heuristically computes the directory in which Etherpad is installed. + * + * All the relative paths have to be interpreted against this absolute base + * path. Since the Unix and Windows install have a different layout on disk, + * they are treated as two special cases. + * + * The path is computed only on first invocation. Subsequent invocations return + * a cached value. + * + * The cached value is stored in AbsolutePaths.etherpadRoot via a side effect. + * + * @return {string} The identified absolute base path. If such path cannot be + * identified, prints a log and exits the application. + */ +exports.findEtherpadRoot = function() { + if (etherpadRoot !== null) { + return etherpadRoot; + } + + const findRoot = require('find-root'); + const foundRoot = findRoot(__dirname); + + var directoriesToStrip; + if (process.platform === 'win32') { + /* + * Given the structure of our Windows package, foundRoot's value + * will be the following on win32: + * + * \node_modules\ep_etherpad-lite + */ + directoriesToStrip = ['node_modules', 'ep_etherpad-lite']; + } else { + /* + * On Unix platforms, foundRoot's value will be: + * + * \src + */ + directoriesToStrip = ['src']; + } + + const maybeEtherpadRoot = popIfEndsWith(foundRoot.split(path.sep), directoriesToStrip); + if (maybeEtherpadRoot === false) { + absPathLogger.error(`Could not identity Etherpad base path in this ${process.platform} installation in "${foundRoot}"`); + process.exit(1); + } + + // SIDE EFFECT on this module-level variable + etherpadRoot = maybeEtherpadRoot.join(path.sep); + + if (path.isAbsolute(etherpadRoot)) { + return etherpadRoot; + } + + absPathLogger.error(`To run, Etherpad has to identify an absolute base path. This is not: "${etherpadRoot}"`); + process.exit(1); +}; diff --git a/src/package.json b/src/package.json index b6df2acb3..bbb069201 100644 --- a/src/package.json +++ b/src/package.json @@ -38,6 +38,7 @@ "etherpad-yajsml": "0.0.2", "express": "4.16.3", "express-session": "1.15.6", + "find-root": "1.1.0", "formidable": "1.2.1", "graceful-fs": "4.1.3", "jsonminify": "0.4.1", From 1b938a7a40a7dee00b3566fb9e47b8427523ac91 Mon Sep 17 00:00:00 2001 From: muxator Date: Wed, 22 Aug 2018 00:47:47 +0200 Subject: [PATCH 009/150] settings: compute exports.root via AbsolutePaths.findEtherpadRoot() First steps for fixing #3466. --- src/node/utils/Settings.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/node/utils/Settings.js b/src/node/utils/Settings.js index 4168ea825..64ea9bf17 100644 --- a/src/node/utils/Settings.js +++ b/src/node/utils/Settings.js @@ -19,6 +19,7 @@ * limitations under the License. */ +var absolutePaths = require('./AbsolutePaths'); var fs = require("fs"); var os = require("os"); var path = require('path'); @@ -31,7 +32,8 @@ var suppressDisableMsg = " -- To suppress these warning messages change suppress var _ = require("underscore"); /* Root path of the installation */ -exports.root = path.normalize(path.join(npm.dir, "..")); +exports.root = absolutePaths.findEtherpadRoot(); +console.log(`All relative paths will be interpreted relative to the identified Etherpad base dir: ${exports.root}`); /** * The app title, visible e.g. in the browser window From 5406472d651e4f27a26e6443c4117aa9bedb9c6b Mon Sep 17 00:00:00 2001 From: muxator Date: Wed, 22 Aug 2018 01:14:30 +0200 Subject: [PATCH 010/150] AbsolutePaths: makeAbsolute() computes an absolute path from a relative one The base is assumed to be exports.findEtherpadRoot(), without depending on process.cwd. --- src/node/utils/AbsolutePaths.js | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/node/utils/AbsolutePaths.js b/src/node/utils/AbsolutePaths.js index 3a7e60f0d..6d67bd15d 100644 --- a/src/node/utils/AbsolutePaths.js +++ b/src/node/utils/AbsolutePaths.js @@ -114,3 +114,24 @@ exports.findEtherpadRoot = function() { absPathLogger.error(`To run, Etherpad has to identify an absolute base path. This is not: "${etherpadRoot}"`); process.exit(1); }; + +/** + * Receives a filesystem path in input. If the path is absolute, returns it + * unchanged. If the path is relative, an absolute version of it is returned, + * built prepending exports.findEtherpadRoot() to it. + * + * @param {string} somePath - an absolute or relative path + * @return {string} An absolute path. If the input path was already absolute, + * it is returned unchanged. Otherwise it is interpreted + * relative to exports.root. + */ +exports.makeAbsolute = function(somePath) { + if (path.isAbsolute(somePath)) { + return somePath; + } + + const rewrittenPath = path.normalize(path.join(exports.findEtherpadRoot(), somePath)); + + absPathLogger.debug(`Relative path "${somePath}" can be rewritten to "${rewrittenPath}"`); + return rewrittenPath; +}; From 435b2a4edf3715e8b8889faebd4964ea5227a2db Mon Sep 17 00:00:00 2001 From: muxator Date: Wed, 22 Aug 2018 01:16:33 +0200 Subject: [PATCH 011/150] settings: the dirtyDb file path is interpreted using makeAbsolute() Otherwise its position depended on process.cwd --- src/node/utils/Settings.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/node/utils/Settings.js b/src/node/utils/Settings.js index 64ea9bf17..bb89d42cf 100644 --- a/src/node/utils/Settings.js +++ b/src/node/utils/Settings.js @@ -499,7 +499,9 @@ exports.reloadSettings = function reloadSettings() { if(!exports.suppressErrorsInPadText){ exports.defaultPadText = exports.defaultPadText + "\nWarning: " + dirtyWarning + suppressDisableMsg; } - console.warn(dirtyWarning); + + exports.dbSettings.filename = absolutePaths.makeAbsolute(exports.dbSettings.filename); + console.warn(dirtyWarning + ` File location: ${exports.dbSettings.filename}`); } }; From 8247d5eef37500589d8c409cf96cf51506e4e71a Mon Sep 17 00:00:00 2001 From: muxator Date: Wed, 22 Aug 2018 00:01:27 +0200 Subject: [PATCH 012/150] settings: use makeAbsolute() for locating settings.json and credentials.json This should look to consistent locations when looking for relative paths, without depending on current working directory. For absolute paths, nothing changes. --- src/node/utils/Settings.js | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/src/node/utils/Settings.js b/src/node/utils/Settings.js index bb89d42cf..6514d2331 100644 --- a/src/node/utils/Settings.js +++ b/src/node/utils/Settings.js @@ -341,20 +341,10 @@ exports.getEpVersion = function() { exports.reloadSettings = function reloadSettings() { // Discover where the settings file lives - var settingsFilename = argv.settings || "settings.json"; - + var settingsFilename = absolutePaths.makeAbsolute(argv.settings || "settings.json"); + // Discover if a credential file exists - var credentialsFilename = argv.credentials || "credentials.json"; - - if (path.resolve(settingsFilename)===settingsFilename) { - settingsFilename = path.resolve(settingsFilename); - } else { - settingsFilename = path.resolve(path.join(exports.root, settingsFilename)); - } - - if (path.resolve(credentialsFilename)===credentialsFilename) { - credentialsFilename = path.resolve(credentialsFilename); - } + var credentialsFilename = absolutePaths.makeAbsolute(argv.credentials || "credentials.json"); var settingsStr, credentialsStr; try{ From ce14a9960610cba75de7de7631eadafbbbe0a3be Mon Sep 17 00:00:00 2001 From: muxator Date: Wed, 22 Aug 2018 01:56:40 +0200 Subject: [PATCH 013/150] settings, APIHandler: use makeAbsolute() for locating APIKEY and SESSIONKEY --- src/node/handler/APIHandler.js | 4 ++-- src/node/utils/Settings.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/node/handler/APIHandler.js b/src/node/handler/APIHandler.js index 3907df79a..7e7da49be 100644 --- a/src/node/handler/APIHandler.js +++ b/src/node/handler/APIHandler.js @@ -18,7 +18,7 @@ * limitations under the License. */ - +var absolutePaths = require('../utils/AbsolutePaths'); var ERR = require("async-stacktrace"); var fs = require("fs"); var api = require("../db/API"); @@ -31,7 +31,7 @@ var apiHandlerLogger = log4js.getLogger('APIHandler'); //ensure we have an apikey var apikey = null; -var apikeyFilename = argv.apikey || "./APIKEY.txt"; +var apikeyFilename = absolutePaths.makeAbsolute(argv.apikey || "./APIKEY.txt"); try { apikey = fs.readFileSync(apikeyFilename,"utf8"); diff --git a/src/node/utils/Settings.js b/src/node/utils/Settings.js index 6514d2331..c4df920b2 100644 --- a/src/node/utils/Settings.js +++ b/src/node/utils/Settings.js @@ -471,7 +471,7 @@ exports.reloadSettings = function reloadSettings() { } if (!exports.sessionKey) { - var sessionkeyFilename = argv.sessionkey || "./SESSIONKEY.txt"; + var sessionkeyFilename = absolutePaths.makeAbsolute(argv.sessionkey || "./SESSIONKEY.txt"); try { exports.sessionKey = fs.readFileSync(sessionkeyFilename,"utf8"); console.info(`Session key loaded from: ${sessionkeyFilename}`); From 0728e667234135bc11bbd85979290ffba949b279 Mon Sep 17 00:00:00 2001 From: "translatewiki.net" Date: Thu, 23 Aug 2018 08:15:56 +0200 Subject: [PATCH 014/150] Localisation updates from https://translatewiki.net. --- src/locales/lt.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/locales/lt.json b/src/locales/lt.json index f0f02d1ea..0dca1db38 100644 --- a/src/locales/lt.json +++ b/src/locales/lt.json @@ -4,7 +4,8 @@ "Eitvys200", "Mantak111", "I-svetaines", - "Zygimantus" + "Zygimantus", + "Vogone" ] }, "index.newPad": "Naujas bloknotas", @@ -54,7 +55,7 @@ "pad.importExport.exportword": "Microsoft Word", "pad.importExport.exportpdf": "PDF", "pad.importExport.exportopen": "ODF (Atvirasis dokumento formatas)", - "pad.importExport.abiword.innerHTML": "Galite importuoti tik iš paprasto teksto ar HTML formato. Dėl išplėstinių importavimo funkcijų prašome įdiegti abiword.", + "pad.importExport.abiword.innerHTML": "Galite importuoti tik iš paprasto teksto ar HTML formato. Dėl išplėstinių importavimo funkcijų prašome įdiegti AbiWord.", "pad.modals.connected": "Prisijungta.", "pad.modals.reconnecting": "Iš naujo prisijungiama prie Jūsų bloknoto", "pad.modals.forcereconnect": "Priversti prisijungti iš naujo", From 9db5fd7884879d055246abf7c92b240ae8735e98 Mon Sep 17 00:00:00 2001 From: muxator Date: Thu, 23 Aug 2018 07:20:17 +0200 Subject: [PATCH 015/150] AbsolutePaths: introduced isSubdir() It can be used to check whether a user input or a configuration settings tries to traverse the directory hierarchy, going out of its allowed bounds. source: https://stackoverflow.com/questions/37521893/determine-if-a-path-is-subdirectory-of-another-in-node-js#45242825 --- src/node/utils/AbsolutePaths.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/node/utils/AbsolutePaths.js b/src/node/utils/AbsolutePaths.js index 6d67bd15d..55dfc98e3 100644 --- a/src/node/utils/AbsolutePaths.js +++ b/src/node/utils/AbsolutePaths.js @@ -135,3 +135,19 @@ exports.makeAbsolute = function(somePath) { absPathLogger.debug(`Relative path "${somePath}" can be rewritten to "${rewrittenPath}"`); return rewrittenPath; }; + +/** + * Returns whether arbitraryDir is a subdirectory of parent. + * + * @param {string} parent - a path to check arbitraryDir against + * @param {string} arbitraryDir - the function will check if this directory is + * a subdirectory of the base one + * @return {boolean} + */ +exports.isSubdir = function(parent, arbitraryDir) { + // modified from: https://stackoverflow.com/questions/37521893/determine-if-a-path-is-subdirectory-of-another-in-node-js#45242825 + const relative = path.relative(parent, arbitraryDir); + const isSubdir = !!relative && !relative.startsWith('..') && !path.isAbsolute(relative); + + return isSubdir; +}; From d1481041c27b24ed2357cd829ef3da85f58f3ff3 Mon Sep 17 00:00:00 2001 From: muxator Date: Thu, 23 Aug 2018 23:39:38 +0200 Subject: [PATCH 016/150] specialpages: replace relative paths for sendfile() with absolute ones This file uses it for robots.txt and favicon.ico. This makes use of the new stable settings.root introduced with #3466, and will be modified when introducing support for custom skins. --- src/node/hooks/express/specialpages.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/node/hooks/express/specialpages.js b/src/node/hooks/express/specialpages.js index 2840f82ca..ec1496499 100644 --- a/src/node/hooks/express/specialpages.js +++ b/src/node/hooks/express/specialpages.js @@ -26,13 +26,13 @@ exports.expressCreateServer = function (hook_name, args, cb) { //serve robots.txt args.app.get('/robots.txt', function(req, res) { - var filePath = path.normalize(__dirname + "/../../../static/custom/robots.txt"); + var filePath = path.join(settings.root, "src", "static", "custom", "robots.txt"); res.sendFile(filePath, function(err) { //there is no custom favicon, send the default robots.txt which dissallows all if(err) { - filePath = path.normalize(__dirname + "/../../../static/robots.txt"); + filePath = path.join(settings.root, "src", "static", "robots.txt"); res.sendFile(filePath); } }); @@ -79,13 +79,14 @@ exports.expressCreateServer = function (hook_name, args, cb) { //serve favicon.ico from all path levels except as a pad name args.app.get( /\/favicon.ico$/, function(req, res) { - var filePath = path.normalize(__dirname + "/../../../static/custom/favicon.ico"); + var filePath = path.join(settings.root, "src", "static", "custom", "favicon.ico"); + res.sendFile(filePath, function(err) { //there is no custom favicon, send the default favicon if(err) { - filePath = path.normalize(__dirname + "/../../../static/favicon.ico"); + filePath = path.join(settings.root, "src", "static", "favicon.ico"); res.sendFile(filePath); } }); From 06476f7ad2e18ff43ae2f925987e908464096f06 Mon Sep 17 00:00:00 2001 From: muxator Date: Fri, 24 Aug 2018 01:26:05 +0200 Subject: [PATCH 017/150] settings.json.template: reorganized dbSetting section to be more comment-friendly It is better to keep the dirtyDB settings together, so they can be commented out via a /* ... */. Nested comments blocks would crash the application on start, because they are syntactically incorrect. Let's reduce this possibility, promoting an easier standard. --- settings.json.template | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/settings.json.template b/settings.json.template index 684e9d598..11d1debc9 100644 --- a/settings.json.template +++ b/settings.json.template @@ -56,18 +56,16 @@ * You shouldn't use "dirty" for for anything else than testing or * development. * - * For a complete list of the supported drivers, please consult: + * + * Database specific settings are dependent on dbType, and go in dbSettings. + * Remember that since Etherpad 1.6.0 you can also store these informations in + * credentials.json. + * + * For a complete list of the supported drivers, please refer to: * https://www.npmjs.com/package/ueberdb2 */ "dbType" : "dirty", - - /* - * Database specific settings (dependent on dbType). - * - * Remember that since Etherpad 1.6.0 you can also store these informations in - * credentials.json. - */ "dbSettings" : { "filename" : "var/dirty.db" }, From 2cc32d7fe9b4933828f94ec855ceb2be6550176c Mon Sep 17 00:00:00 2001 From: Luc Didry Date: Fri, 24 Aug 2018 10:28:57 +0200 Subject: [PATCH 018/150] Add --writer option to soffice convert command If you edit `src/templates/export_html.html` to remove the `` tag[1], PDF export with soffice has a bug: the first word of the pad is deleted and a blank page is inserted as first page (the pad's text begins on the second page). The `--writer` soffice option avoids that bug. [1] you may want to delete that tag since it is inserted as a comment in .doc or .odt soffice export. --- src/node/utils/LibreOffice.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/node/utils/LibreOffice.js b/src/node/utils/LibreOffice.js index 3cf63e1d6..9127d18d2 100644 --- a/src/node/utils/LibreOffice.js +++ b/src/node/utils/LibreOffice.js @@ -63,6 +63,7 @@ function doConvertTask(task, callback) { '--invisible', '--nologo', '--nolockcheck', + '--writer', '--convert-to', task.type, task.srcFile, '--outdir', tmpDir From 6c56e7ca7aeaf095b4ec153b00868b465f439f21 Mon Sep 17 00:00:00 2001 From: muxator Date: Sun, 26 Aug 2018 02:40:36 +0200 Subject: [PATCH 019/150] ace.js: use URL encoding when building an URL via string concatenation Not performing encoding/decoding when traversing logical domains is a security risk. String concatenation is not great, too, but this change is just focused on allowing the implementation of skin support. --- src/static/js/ace.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/static/js/ace.js b/src/static/js/ace.js index 9f219e6c2..3b8679b45 100644 --- a/src/static/js/ace.js +++ b/src/static/js/ace.js @@ -186,7 +186,7 @@ function Ace2Editor() } for (var i = 0, ii = remoteFiles.length; i < ii; i++) { var file = remoteFiles[i]; - buffer.push(''); + buffer.push(''); } } From 0c518cadf5ee7acbde70d6ad2bbab7e76075e266 Mon Sep 17 00:00:00 2001 From: muxator Date: Sun, 26 Aug 2018 01:11:02 +0200 Subject: [PATCH 020/150] skins: replace {js,css}.template with actual files. Simplify startup scripts. Currently, an Etherpad skin requires the existence of 6 files: - index.{css,js} - pad.{css,js} - timeslider.{css,js} In the default empty skin (in static/custom), there were 2 small placeholders ({js,css}.template) to be copied in place by the startup script in case no skin was in use. Now that we are moving to multiple directories (see #3471) we can simply commit the example files and remove the copying code from the startup script. --- bin/installDeps.sh | 13 ------------- bin/installOnWindows.bat | 10 +--------- src/static/custom/.gitignore | 3 --- src/static/custom/{css.template => index.css} | 0 src/static/custom/{js.template => index.js} | 0 src/static/custom/pad.css | 8 ++++++++ src/static/custom/pad.js | 6 ++++++ src/static/custom/timeslider.css | 8 ++++++++ src/static/custom/timeslider.js | 6 ++++++ 9 files changed, 29 insertions(+), 25 deletions(-) delete mode 100644 src/static/custom/.gitignore rename src/static/custom/{css.template => index.css} (100%) rename src/static/custom/{js.template => index.js} (100%) create mode 100644 src/static/custom/pad.css create mode 100644 src/static/custom/pad.js create mode 100644 src/static/custom/timeslider.css create mode 100644 src/static/custom/timeslider.js diff --git a/bin/installDeps.sh b/bin/installDeps.sh index 47373a5f6..dd7052390 100755 --- a/bin/installDeps.sh +++ b/bin/installDeps.sh @@ -143,17 +143,4 @@ fi echo "Clearing minified cache..." rm -f var/minified* -echo "Ensure custom css/js files are created..." - -for f in "index" "pad" "timeslider" -do - if [ ! -f "src/static/custom/$f.js" ]; then - cp "src/static/custom/js.template" "src/static/custom/$f.js" || exit 1 - fi - - if [ ! -f "src/static/custom/$f.css" ]; then - cp "src/static/custom/css.template" "src/static/custom/$f.css" || exit 1 - fi -done - exit 0 diff --git a/bin/installOnWindows.bat b/bin/installOnWindows.bat index 5ba057365..75982aaff 100644 --- a/bin/installOnWindows.bat +++ b/bin/installOnWindows.bat @@ -18,14 +18,6 @@ cmd /C npm install --loglevel warn || exit /B 1 cd /D "%~dp0\.." -echo _ -echo Copying custom templates... -set custom_dir=node_modules\ep_etherpad-lite\static\custom -FOR %%f IN (index pad timeslider) DO ( - if NOT EXIST "%custom_dir%\%%f.js" copy "%custom_dir%\js.template" "%custom_dir%\%%f.js" - if NOT EXIST "%custom_dir%\%%f.css" copy "%custom_dir%\css.template" "%custom_dir%\%%f.css" -) - echo _ echo Clearing cache... del /S var\minified* @@ -39,4 +31,4 @@ IF NOT EXIST settings.json ( ) echo _ -echo Installed Etherpad! To run Etherpad type start.bat \ No newline at end of file +echo Installed Etherpad! To run Etherpad type start.bat diff --git a/src/static/custom/.gitignore b/src/static/custom/.gitignore deleted file mode 100644 index aae16bb24..000000000 --- a/src/static/custom/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -* -!.gitignore -!*.template diff --git a/src/static/custom/css.template b/src/static/custom/index.css similarity index 100% rename from src/static/custom/css.template rename to src/static/custom/index.css diff --git a/src/static/custom/js.template b/src/static/custom/index.js similarity index 100% rename from src/static/custom/js.template rename to src/static/custom/index.js diff --git a/src/static/custom/pad.css b/src/static/custom/pad.css new file mode 100644 index 000000000..236251d9c --- /dev/null +++ b/src/static/custom/pad.css @@ -0,0 +1,8 @@ +/* + custom css files are loaded after core css files. Simply use the same selector to override a style. + Example: + #editbar LI {border:1px solid #000;} + overrides + #editbar LI {border:1px solid #d5d5d5;} + from pad.css +*/ diff --git a/src/static/custom/pad.js b/src/static/custom/pad.js new file mode 100644 index 000000000..152c3d5d7 --- /dev/null +++ b/src/static/custom/pad.js @@ -0,0 +1,6 @@ +function customStart() +{ + //define your javascript here + //jquery is available - except index.js + //you can load extra scripts with $.getScript http://api.jquery.com/jQuery.getScript/ +} diff --git a/src/static/custom/timeslider.css b/src/static/custom/timeslider.css new file mode 100644 index 000000000..236251d9c --- /dev/null +++ b/src/static/custom/timeslider.css @@ -0,0 +1,8 @@ +/* + custom css files are loaded after core css files. Simply use the same selector to override a style. + Example: + #editbar LI {border:1px solid #000;} + overrides + #editbar LI {border:1px solid #d5d5d5;} + from pad.css +*/ diff --git a/src/static/custom/timeslider.js b/src/static/custom/timeslider.js new file mode 100644 index 000000000..152c3d5d7 --- /dev/null +++ b/src/static/custom/timeslider.js @@ -0,0 +1,6 @@ +function customStart() +{ + //define your javascript here + //jquery is available - except index.js + //you can load extra scripts with $.getScript http://api.jquery.com/jQuery.getScript/ +} From aba1c6f8bd0558de82b4303dc55775d8c74843c5 Mon Sep 17 00:00:00 2001 From: muxator Date: Sun, 26 Aug 2018 01:24:01 +0200 Subject: [PATCH 021/150] skins: moved "static/custom" -> "static/skins/no-skin" The old empty skin created by the startup scripts becomes the default: no-skin. --- src/static/{custom => skins/no-skin}/index.css | 0 src/static/{custom => skins/no-skin}/index.js | 0 src/static/{custom => skins/no-skin}/pad.css | 0 src/static/{custom => skins/no-skin}/pad.js | 0 src/static/{custom => skins/no-skin}/timeslider.css | 0 src/static/{custom => skins/no-skin}/timeslider.js | 0 6 files changed, 0 insertions(+), 0 deletions(-) rename src/static/{custom => skins/no-skin}/index.css (100%) rename src/static/{custom => skins/no-skin}/index.js (100%) rename src/static/{custom => skins/no-skin}/pad.css (100%) rename src/static/{custom => skins/no-skin}/pad.js (100%) rename src/static/{custom => skins/no-skin}/timeslider.css (100%) rename src/static/{custom => skins/no-skin}/timeslider.js (100%) diff --git a/src/static/custom/index.css b/src/static/skins/no-skin/index.css similarity index 100% rename from src/static/custom/index.css rename to src/static/skins/no-skin/index.css diff --git a/src/static/custom/index.js b/src/static/skins/no-skin/index.js similarity index 100% rename from src/static/custom/index.js rename to src/static/skins/no-skin/index.js diff --git a/src/static/custom/pad.css b/src/static/skins/no-skin/pad.css similarity index 100% rename from src/static/custom/pad.css rename to src/static/skins/no-skin/pad.css diff --git a/src/static/custom/pad.js b/src/static/skins/no-skin/pad.js similarity index 100% rename from src/static/custom/pad.js rename to src/static/skins/no-skin/pad.js diff --git a/src/static/custom/timeslider.css b/src/static/skins/no-skin/timeslider.css similarity index 100% rename from src/static/custom/timeslider.css rename to src/static/skins/no-skin/timeslider.css diff --git a/src/static/custom/timeslider.js b/src/static/skins/no-skin/timeslider.js similarity index 100% rename from src/static/custom/timeslider.js rename to src/static/skins/no-skin/timeslider.js From 7edc0fea162ce58c7249caa57a80531c1c164cbf Mon Sep 17 00:00:00 2001 From: muxator Date: Sun, 19 Aug 2018 01:06:24 +0200 Subject: [PATCH 022/150] skins: added new parameter "skinName" in setting.json.template "colibris" does not exist yet, but let's mention it anyway. --- settings.json.template | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/settings.json.template b/settings.json.template index 11d1debc9..a89cc4247 100644 --- a/settings.json.template +++ b/settings.json.template @@ -18,6 +18,19 @@ */ "favicon": "favicon.ico", + /* + * Skin name. + * + * Its value has to be an existing directory under src/static/skins. + * You can write your own, or use one of the included ones: + * + * - "no-skin": an empty skin (default). This yields the unmodified, + * traditional Etherpad theme. + * - "colibris": the new experimental skin (since Etherpad 1.8), candidate to + * become the default in Etherpad 2.0 + */ + "skinName": "no-skin", + /* * IP and port which etherpad should bind at */ From e34c74b24d4f81259c72cc8d5314acff8915becc Mon Sep 17 00:00:00 2001 From: muxator Date: Sun, 19 Aug 2018 03:36:18 +0200 Subject: [PATCH 023/150] skins: the settings class understands skinName. Send skinName value to the client skinName must be a single string (no directory separators in it) pointing to an existing directory under /src/static/skins. In case these conditions are not met, its value is rewritten to "no-skin". Also, the value of skinName if sent to the client via clientVars for allowing its use it in the browser. --- src/node/handler/PadMessageHandler.js | 1 + src/node/utils/Settings.js | 44 +++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/src/node/handler/PadMessageHandler.js b/src/node/handler/PadMessageHandler.js index b575125a2..d316faf01 100644 --- a/src/node/handler/PadMessageHandler.js +++ b/src/node/handler/PadMessageHandler.js @@ -1268,6 +1268,7 @@ function handleClientReady(client, message) // client is read only you would open a security hole 1 swedish // mile wide... var clientVars = { + "skinName": settings.skinName, "accountPrivs": { "maxRevisions": 100 }, diff --git a/src/node/utils/Settings.js b/src/node/utils/Settings.js index c4df920b2..6a93b8191 100644 --- a/src/node/utils/Settings.js +++ b/src/node/utils/Settings.js @@ -47,6 +47,14 @@ exports.favicon = "favicon.ico"; exports.faviconPad = "../" + exports.favicon; exports.faviconTimeslider = "../../" + exports.favicon; +/* + * Skin name. + * + * Initialized to null, so we can spot an old configuration file and invite the + * user to update it before falling back to the default. + */ +exports.skinName = null; + /** * The IP ep-lite should listen to */ @@ -439,6 +447,42 @@ exports.reloadSettings = function reloadSettings() { process.env['DEBUG'] = 'socket.io:' + exports.loglevel; // Used by SocketIO for Debug log4js.replaceConsole(); + if (!exports.skinName) { + console.warn(`No "skinName" parameter found. Please consult settings.json.template and update your settings.json. Falling back to the default "no-skin".`); + exports.skinName = "no-skin"; + } + + // checks if skinName has an acceptable value, otherwise falls back to "no-skin" + if (exports.skinName) { + const skinBasePath = path.join(exports.root, "src", "static", "skins"); + const countPieces = exports.skinName.split(path.sep).length; + + if (countPieces != 1) { + console.error(`skinName must be the name of a directory under "${skinBasePath}". This is not valid: "${exports.skinName}". Falling back to the default "no-skin".`); + + exports.skinName = "no-skin"; + } + + // informative variable, just for the log messages + var skinPath = path.normalize(path.join(skinBasePath, exports.skinName)); + + // what if someone sets skinName == ".." or "."? We catch him! + if (absolutePaths.isSubdir(skinBasePath, skinPath) === false) { + console.error(`Skin path ${skinPath} must be a subdirectory of ${skinBasePath}. Falling back to the default "no-skin".`); + + exports.skinName = "no-skin"; + skinPath = path.join(skinBasePath, exports.skinName); + } + + if (fs.existsSync(skinPath) === false) { + console.error(`Skin path ${skinPath} does not exist. Falling back to the default "no-skin".`); + exports.skinName = "no-skin"; + skinPath = path.join(skinBasePath, exports.skinName); + } + + console.info(`Using skin "${exports.skinName}" in dir: ${skinPath}`); + } + if(exports.abiword){ // Check abiword actually exists if(exports.abiword != null) From 9c990ab08a51b921af8973dff8e7eddefa252b98 Mon Sep 17 00:00:00 2001 From: muxator Date: Sun, 26 Aug 2018 03:43:53 +0200 Subject: [PATCH 024/150] skins: finalize support for multiple skins The old "static/custom" directory is replaced by "static/skins/", where is taken from settings.json. When no value is found, a default of "no-skin" is assumed, so that backward compatibility is maintained. The most evident security concerns have been addressed. Closes #3471. --- src/node/hooks/express/specialpages.js | 4 ++-- src/static/js/ace.js | 4 ++-- src/templates/index.html | 4 ++-- src/templates/javascript.html | 12 ++++++------ src/templates/pad.html | 4 ++-- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/node/hooks/express/specialpages.js b/src/node/hooks/express/specialpages.js index ec1496499..69d23ff6d 100644 --- a/src/node/hooks/express/specialpages.js +++ b/src/node/hooks/express/specialpages.js @@ -26,7 +26,7 @@ exports.expressCreateServer = function (hook_name, args, cb) { //serve robots.txt args.app.get('/robots.txt', function(req, res) { - var filePath = path.join(settings.root, "src", "static", "custom", "robots.txt"); + var filePath = path.join(settings.root, "src", "static", "skins", settings.skinName, "robots.txt"); res.sendFile(filePath, function(err) { //there is no custom favicon, send the default robots.txt which dissallows all @@ -79,7 +79,7 @@ exports.expressCreateServer = function (hook_name, args, cb) { //serve favicon.ico from all path levels except as a pad name args.app.get( /\/favicon.ico$/, function(req, res) { - var filePath = path.join(settings.root, "src", "static", "custom", "favicon.ico"); + var filePath = path.join(settings.root, "src", "static", "skins", settings.skinName, "favicon.ico"); res.sendFile(filePath, function(err) { diff --git a/src/static/js/ace.js b/src/static/js/ace.js index 3b8679b45..2f9c1e6da 100644 --- a/src/static/js/ace.js +++ b/src/static/js/ace.js @@ -230,7 +230,7 @@ function Ace2Editor() // disableCustomScriptsAndStyles can be used to disable loading of custom scripts if(!clientVars.disableCustomScriptsAndStyles){ $$INCLUDE_CSS("../static/css/pad.css"); - $$INCLUDE_CSS("../static/custom/pad.css"); + $$INCLUDE_CSS(`../static/skins/${clientVars.skinName}/pad.css`); } var additionalCSS = _(hooks.callAll("aceEditorCSS")).map(function(path){ @@ -314,7 +314,7 @@ window.onload = function () {\n\ var $$INCLUDE_CSS = function(filename) {includedCSS.push(filename)}; $$INCLUDE_CSS("../static/css/iframe_editor.css"); $$INCLUDE_CSS("../static/css/pad.css"); - $$INCLUDE_CSS("../static/custom/pad.css"); + $$INCLUDE_CSS(`../static/skins/${clientVars.skinName}/pad.css`); var additionalCSS = _(hooks.callAll("aceEditorCSS")).map(function(path){ diff --git a/src/templates/index.html b/src/templates/index.html index 92bea582a..87fe0ee78 100644 --- a/src/templates/index.html +++ b/src/templates/index.html @@ -156,7 +156,7 @@ } } - +
<% e.begin_block("indexWrapper"); %> @@ -171,7 +171,7 @@ <% e.end_block(); %>
- + <% e.begin_block("customScripts"); %> - + <% e.end_block(); %> From 6620014b775f570d6778fce8de119fa02b0f2c40 Mon Sep 17 00:00:00 2001 From: muxator Date: Sun, 26 Aug 2018 21:12:13 +0200 Subject: [PATCH 025/150] skins: describe the skins in the documentation --- doc/custom_static.md | 11 ----------- doc/index.md | 2 +- doc/skins.md | 19 +++++++++++++++++++ 3 files changed, 20 insertions(+), 12 deletions(-) delete mode 100644 doc/custom_static.md create mode 100644 doc/skins.md diff --git a/doc/custom_static.md b/doc/custom_static.md deleted file mode 100644 index 7bb290094..000000000 --- a/doc/custom_static.md +++ /dev/null @@ -1,11 +0,0 @@ -# Custom static files -Etherpad allows you to include your own static files in the browser, by modifying the files in `static/custom`. - -* `index.js` Javascript that'll be run in `/` -* `index.css` Stylesheet affecting `/` -* `pad.js` Javascript that'll be run in `/p/:padid` -* `pad.css` Stylesheet affecting `/p/:padid` -* `timeslider.js` Javascript that'll be run in `/p/:padid/timeslider` -* `timeslider.css` Stylesheet affecting `/p/:padid/timeslider` -* `favicon.ico` Overrides the default favicon. -* `robots.txt` Overrides the default `robots.txt`. \ No newline at end of file diff --git a/doc/index.md b/doc/index.md index 09553f686..5b93bac68 100644 --- a/doc/index.md +++ b/doc/index.md @@ -1,7 +1,7 @@ @include documentation @include stats @include localization -@include custom_static +@include skins @include api/api @include plugins @include database diff --git a/doc/skins.md b/doc/skins.md new file mode 100644 index 000000000..1431dac8d --- /dev/null +++ b/doc/skins.md @@ -0,0 +1,19 @@ +# Skins +You can customize Etherpad appearance using skins. +A skin is a directory located under `static/skins/`, with the following contents: + +* `index.js`: javascript that will be run in `/` +* `index.css`: stylesheet affecting `/` +* `pad.js`: javascript that will be run in `/p/:padid` +* `pad.css`: stylesheet affecting `/p/:padid` +* `timeslider.js`: javascript that will be run in `/p/:padid/timeslider` +* `timeslider.css`: stylesheet affecting `/p/:padid/timeslider` +* `favicon.ico`: overrides the default favicon +* `robots.txt`: overrides the default `robots.txt` + +You can choose a skin changing the parameter `skinName` in `settings.json`. + +Since Etherpad **1.8**, two skins are included: + +* `no-skin`: an empty skin, leaving the default Etherpad appearance unchanged, that you can use as a guidance to develop your own. +* `colibris`: a new, experimental skin, that will become the default in Etherpad 2.0. From 7f7efa22b7330416b6369b04a4862b0878d88a52 Mon Sep 17 00:00:00 2001 From: muxator Date: Sun, 26 Aug 2018 22:28:31 +0200 Subject: [PATCH 026/150] javascript license: we cannot assert the license of a custom skin. Even in the previous versions, it made no sense. Removing. --- src/templates/javascript.html | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/src/templates/javascript.html b/src/templates/javascript.html index a90383818..7bc92e05f 100644 --- a/src/templates/javascript.html +++ b/src/templates/javascript.html @@ -33,21 +33,6 @@ Expat require-kernel.js - - index.js - Apache-2.0-only - index.js - - - timeslider.js - Apache-2.0-only - timeslider.js - - - pad.js - Apache-2.0-only - pad.js - plugins.js Apache-2.0-only From 36f39a6e13d3713dd45f0def014ee2403d0b24f9 Mon Sep 17 00:00:00 2001 From: muxator Date: Mon, 27 Aug 2018 02:18:34 +0200 Subject: [PATCH 027/150] ace.js: remove template literals to keep IE 11 compatibility Files in "src/static" are executed on the client: do not break browser compatibility because of syntactic sugar. Introduced in 9c990ab08a51. --- src/static/js/ace.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/static/js/ace.js b/src/static/js/ace.js index 2f9c1e6da..bbf83c0e7 100644 --- a/src/static/js/ace.js +++ b/src/static/js/ace.js @@ -230,7 +230,7 @@ function Ace2Editor() // disableCustomScriptsAndStyles can be used to disable loading of custom scripts if(!clientVars.disableCustomScriptsAndStyles){ $$INCLUDE_CSS("../static/css/pad.css"); - $$INCLUDE_CSS(`../static/skins/${clientVars.skinName}/pad.css`); + $$INCLUDE_CSS("../static/skins/" + clientVars.skinName + "/pad.css"); } var additionalCSS = _(hooks.callAll("aceEditorCSS")).map(function(path){ @@ -314,7 +314,7 @@ window.onload = function () {\n\ var $$INCLUDE_CSS = function(filename) {includedCSS.push(filename)}; $$INCLUDE_CSS("../static/css/iframe_editor.css"); $$INCLUDE_CSS("../static/css/pad.css"); - $$INCLUDE_CSS(`../static/skins/${clientVars.skinName}/pad.css`); + $$INCLUDE_CSS("../static/skins/" + clientVars.skinName + "/pad.css"); var additionalCSS = _(hooks.callAll("aceEditorCSS")).map(function(path){ From 0e972aaecfec51dec86b3c63200fee8e7d0be2c7 Mon Sep 17 00:00:00 2001 From: muxator Date: Mon, 27 Aug 2018 01:56:33 +0200 Subject: [PATCH 028/150] settings: reword some log messages --- src/node/utils/Settings.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/node/utils/Settings.js b/src/node/utils/Settings.js index 6a93b8191..648ecbbbd 100644 --- a/src/node/utils/Settings.js +++ b/src/node/utils/Settings.js @@ -393,10 +393,10 @@ exports.reloadSettings = function reloadSettings() { //loop trough the settings for(var i in settings) { - //test if the setting start with a low character + //test if the setting start with a lowercase character if(i.charAt(0).search("[a-z]") !== 0) { - console.warn("Settings should start with a low character: '" + i + "'"); + console.warn("Settings should start with a lowercase character: '" + i + "'"); } //we know this setting, so we overwrite it @@ -419,10 +419,10 @@ exports.reloadSettings = function reloadSettings() { //loop trough the settings for(var i in credentials) { - //test if the setting start with a low character + //test if the setting start with a lowercase character if(i.charAt(0).search("[a-z]") !== 0) { - console.warn("Settings should start with a low character: '" + i + "'"); + console.warn("Settings should start with a lowercase character: '" + i + "'"); } //we know this setting, so we overwrite it @@ -448,7 +448,7 @@ exports.reloadSettings = function reloadSettings() { log4js.replaceConsole(); if (!exports.skinName) { - console.warn(`No "skinName" parameter found. Please consult settings.json.template and update your settings.json. Falling back to the default "no-skin".`); + console.warn(`No "skinName" parameter found. Please check out settings.json.template and update your settings.json. Falling back to the default "no-skin".`); exports.skinName = "no-skin"; } From 27b3b0ecd24faee7f511dd7fbae1af13cbd59cf5 Mon Sep 17 00:00:00 2001 From: muxator Date: Mon, 27 Aug 2018 01:29:37 +0200 Subject: [PATCH 029/150] logs: on the server, use template literals when possible It's just synctactic sugar, but it is always better than executing string concatenations in one's mind. Do not do this with files in src/static, because we want to keep IE 11 compatibility. --- src/node/db/SessionManager.js | 2 +- src/node/hooks/express.js | 14 +++++++------- src/node/utils/Abiword.js | 4 ++-- src/node/utils/LibreOffice.js | 2 +- src/node/utils/Settings.js | 8 ++++---- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/node/db/SessionManager.js b/src/node/db/SessionManager.js index f8000e47e..518c70c7a 100644 --- a/src/node/db/SessionManager.js +++ b/src/node/db/SessionManager.js @@ -353,7 +353,7 @@ function listSessionsWithDBKey (dbkey, callback) { if (err == "apierror: sessionID does not exist") { - console.warn("Found bad session " + sessionID + " in " + dbkey + "."); + console.warn(`Found bad session ${sessionID} in ${dbkey}`); } else if(ERR(err, callback)) { diff --git a/src/node/hooks/express.js b/src/node/hooks/express.js index 48dcf56cb..e7b373805 100644 --- a/src/node/hooks/express.js +++ b/src/node/hooks/express.js @@ -12,15 +12,15 @@ var serverName; exports.createServer = function () { console.log("Report bugs at https://github.com/ether/etherpad-lite/issues") - serverName = "Etherpad " + settings.getGitCommit() + " (http://etherpad.org)"; + serverName = `Etherpad ${settings.getGitCommit()} (http://etherpad.org)`; - console.log("Your Etherpad version is " + settings.getEpVersion() + " (" + settings.getGitCommit() + ")"); + console.log(`Your Etherpad version is ${settings.getEpVersion()} (${settings.getGitCommit()})`); exports.restartServer(); - console.log("You can access your Etherpad instance at http://" + settings.ip + ":" + settings.port + "/"); + console.log(`You can access your Etherpad instance at http://${settings.ip}:${settings.port}/`); if(!_.isEmpty(settings.users)){ - console.log("The plugin admin page is at http://" + settings.ip + ":" + settings.port + "/admin/plugins"); + console.log(`The plugin admin page is at http://${settings.ip}:${settings.port}/admin/plugins`); } else{ console.warn("Admin username and password not set in settings.json. To access admin please uncomment and edit 'users' in settings.json"); @@ -42,9 +42,9 @@ exports.restartServer = function () { if (settings.ssl) { - console.log( "SSL -- enabled"); - console.log( "SSL -- server key file: " + settings.ssl.key ); - console.log( "SSL -- Certificate Authority's certificate file: " + settings.ssl.cert ); + console.log("SSL -- enabled"); + console.log(`SSL -- server key file: ${settings.ssl.key}`); + console.log(`SSL -- Certificate Authority's certificate file: ${settings.ssl.cert}`); var options = { key: fs.readFileSync( settings.ssl.key ), diff --git a/src/node/utils/Abiword.js b/src/node/utils/Abiword.js index 1d9ac5d30..2aae5a8ac 100644 --- a/src/node/utils/Abiword.js +++ b/src/node/utils/Abiword.js @@ -52,7 +52,7 @@ if(os.type().indexOf("Windows") > -1) abiword.on('exit', function (code) { if(code != 0) { - return callback("Abiword died with exit code " + code); + return callback(`Abiword died with exit code ${code}`); } if(stdoutBuffer != "") @@ -91,7 +91,7 @@ else abiword.on('exit', function (code) { spawnAbiword(); - stdoutCallback("Abiword died with exit code " + code); + stdoutCallback(`Abiword died with exit code ${code}`); }); //delegate the processing of stdout to a other function diff --git a/src/node/utils/LibreOffice.js b/src/node/utils/LibreOffice.js index 9127d18d2..6f049d224 100644 --- a/src/node/utils/LibreOffice.js +++ b/src/node/utils/LibreOffice.js @@ -84,7 +84,7 @@ function doConvertTask(task, callback) { // Throw an exception if libreoffice failed soffice.on('exit', function(code) { if (code != 0) { - return callback("LibreOffice died with exit code " + code + " and message: " + stdoutBuffer); + return callback(`LibreOffice died with exit code ${code} and message: ${stdoutBuffer}`); } callback(); diff --git a/src/node/utils/Settings.js b/src/node/utils/Settings.js index 648ecbbbd..508e6148d 100644 --- a/src/node/utils/Settings.js +++ b/src/node/utils/Settings.js @@ -396,7 +396,7 @@ exports.reloadSettings = function reloadSettings() { //test if the setting start with a lowercase character if(i.charAt(0).search("[a-z]") !== 0) { - console.warn("Settings should start with a lowercase character: '" + i + "'"); + console.warn(`Settings should start with a lowercase character: '${i}'`); } //we know this setting, so we overwrite it @@ -412,7 +412,7 @@ exports.reloadSettings = function reloadSettings() { //this setting is unkown, output a warning and throw it away else { - console.warn("Unknown Setting: '" + i + "'. This setting doesn't exist or it was removed"); + console.warn(`Unknown Setting: '${i}'. This setting doesn't exist or it was removed`); } } @@ -422,7 +422,7 @@ exports.reloadSettings = function reloadSettings() { //test if the setting start with a lowercase character if(i.charAt(0).search("[a-z]") !== 0) { - console.warn("Settings should start with a lowercase character: '" + i + "'"); + console.warn(`Settings should start with a lowercase character: '${i}'`); } //we know this setting, so we overwrite it @@ -438,7 +438,7 @@ exports.reloadSettings = function reloadSettings() { //this setting is unkown, output a warning and throw it away else { - console.warn("Unknown Setting: '" + i + "'. This setting doesn't exist or it was removed"); + console.warn(`Unknown Setting: '${i}'. This setting doesn't exist or it was removed`); } } From fb1f8dd239c6362520a0f28bf6b9146fa7b4047a Mon Sep 17 00:00:00 2001 From: muxator Date: Mon, 27 Aug 2018 01:34:01 +0200 Subject: [PATCH 030/150] toolbar: missing var declaration Without this, Etherpad would fail to start in strict mode: "ReferenceError: SelectButton is not defined" --- src/node/utils/toolbar.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/node/utils/toolbar.js b/src/node/utils/toolbar.js index eaa1d4217..67ce12593 100644 --- a/src/node/utils/toolbar.js +++ b/src/node/utils/toolbar.js @@ -116,7 +116,7 @@ _.extend(Button.prototype, { -SelectButton = function (attributes) { +var SelectButton = function (attributes) { this.attributes = attributes; this.options = []; }; From c0e257835c0ccb50b4ec58701621ad9dcac16af9 Mon Sep 17 00:00:00 2001 From: anoy Date: Mon, 27 Aug 2018 10:05:35 +0200 Subject: [PATCH 031/150] updated nodejs version for travisci --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 908aca419..72ae8027b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ language: node_js node_js: - - "0.10" + - "lts/*" install: - "bin/installDeps.sh" - "export GIT_HASH=$(git rev-parse --verify --short HEAD)" From 07bc163cb698768020cb4d41808f1cd92c0d1b7b Mon Sep 17 00:00:00 2001 From: anoy Date: Mon, 27 Aug 2018 12:59:06 +0200 Subject: [PATCH 032/150] url encode pad name --- src/templates/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/templates/index.html b/src/templates/index.html index 87fe0ee78..872367c9a 100644 --- a/src/templates/index.html +++ b/src/templates/index.html @@ -177,7 +177,7 @@ function go2Name() { var padname = document.getElementById("padname").value; - padname.length > 0 ? window.location = "p/" + padname : alert("Please enter a name") + padname.length > 0 ? window.location = "p/" + encodeURIComponent(padname.trim()) : alert("Please enter a name") } function go2Random() From 324929ca2d70446d9d1c2cca3c73d89a6d3c5734 Mon Sep 17 00:00:00 2001 From: muxator Date: Wed, 29 Aug 2018 00:57:28 +0200 Subject: [PATCH 033/150] PadMessageHandler: early return to reduce code depth. Get rid of an else branch to simplify code layout. No functional changes at all. ============== This series is an attempt to reduce the control structure depth of the code base, maintaining at the same time its exact same behaviour, bugs included. It is, in a sense, an initial attempt at a refactoring in the spirit of its original definition [0]. The idea beyond this refactoring is that reducing the code depth and, sometimes, inverting some conditions, bugs and logic errors may become easier to spot, and the code easier to read. When looked at ignoring whitespace changes, all of these diffs should appear trivial. [0] https://refactoring.com/ --- src/node/handler/PadMessageHandler.js | 51 ++++++++++++++------------- 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/src/node/handler/PadMessageHandler.js b/src/node/handler/PadMessageHandler.js index d316faf01..767348d2a 100644 --- a/src/node/handler/PadMessageHandler.js +++ b/src/node/handler/PadMessageHandler.js @@ -265,33 +265,34 @@ exports.handleMessage = function(client, message) if(!sessioninfos[client.id].auth){ console.error("Auth was never applied to a session. If you are using the stress-test tool then restart Etherpad and the Stress test tool.") return; - }else{ - var auth = sessioninfos[client.id].auth; - var checkAccessCallback = function(err, statusObject) - { - if(ERR(err, callback)) return; + } - //access was granted - if(statusObject.accessStatus == "grant") - { - callback(); - } - //no access, send the client a message that tell him why - else - { - client.json.send({accessStatus: statusObject.accessStatus}) - } - }; - //check if pad is requested via readOnly - if (auth.padID.indexOf("r.") === 0) { - //Pad is readOnly, first get the real Pad ID - readOnlyManager.getPadId(auth.padID, function(err, value) { - ERR(err); - securityManager.checkAccess(value, auth.sessionID, auth.token, auth.password, checkAccessCallback); - }); - } else { - securityManager.checkAccess(auth.padID, auth.sessionID, auth.token, auth.password, checkAccessCallback); + var auth = sessioninfos[client.id].auth; + var checkAccessCallback = function(err, statusObject) + { + if(ERR(err, callback)) return; + + //access was granted + if(statusObject.accessStatus == "grant") + { + callback(); } + //no access, send the client a message that tell him why + else + { + client.json.send({accessStatus: statusObject.accessStatus}) + } + }; + + //check if pad is requested via readOnly + if (auth.padID.indexOf("r.") === 0) { + //Pad is readOnly, first get the real Pad ID + readOnlyManager.getPadId(auth.padID, function(err, value) { + ERR(err); + securityManager.checkAccess(value, auth.sessionID, auth.token, auth.password, checkAccessCallback); + }); + } else { + securityManager.checkAccess(auth.padID, auth.sessionID, auth.token, auth.password, checkAccessCallback); } }, finalHandler From b60c0b122ce1a3413cc4c974c267f7619364e82b Mon Sep 17 00:00:00 2001 From: muxator Date: Wed, 29 Aug 2018 01:23:38 +0200 Subject: [PATCH 034/150] PadMessageHandler: reversed condition to make core logic evident. No behavioural changes. This one replaces a big "if (message)" negating its truthy condition. Being lame, I erred on the safe side and wrote a super ugly statement that is guaranteed to respect the original logic. In the hope that eventual logic errors become more evident now. See: https://stackoverflow.com/questions/36661748/what-is-the-exact-negation-of-ifvariable-in-javascript#36661843 --- src/node/handler/PadMessageHandler.js | 117 ++++++++++++++------------ 1 file changed, 64 insertions(+), 53 deletions(-) diff --git a/src/node/handler/PadMessageHandler.js b/src/node/handler/PadMessageHandler.js index 767348d2a..c52565de3 100644 --- a/src/node/handler/PadMessageHandler.js +++ b/src/node/handler/PadMessageHandler.js @@ -244,60 +244,71 @@ exports.handleMessage = function(client, message) } }; - if (message) { - async.series([ - handleMessageHook, - //check permissions - function(callback) - { - // client tried to auth for the first time (first msg from the client) - if(message.type == "CLIENT_READY") { - createSessionInfo(client, message); - } - - // Note: message.sessionID is an entirely different kind of - // session from the sessions we use here! Beware! - // FIXME: Call our "sessions" "connections". - // FIXME: Use a hook instead - // FIXME: Allow to override readwrite access with readonly - - // Simulate using the load testing tool - if(!sessioninfos[client.id].auth){ - console.error("Auth was never applied to a session. If you are using the stress-test tool then restart Etherpad and the Stress test tool.") - return; - } - - var auth = sessioninfos[client.id].auth; - var checkAccessCallback = function(err, statusObject) - { - if(ERR(err, callback)) return; - - //access was granted - if(statusObject.accessStatus == "grant") - { - callback(); - } - //no access, send the client a message that tell him why - else - { - client.json.send({accessStatus: statusObject.accessStatus}) - } - }; - - //check if pad is requested via readOnly - if (auth.padID.indexOf("r.") === 0) { - //Pad is readOnly, first get the real Pad ID - readOnlyManager.getPadId(auth.padID, function(err, value) { - ERR(err); - securityManager.checkAccess(value, auth.sessionID, auth.token, auth.password, checkAccessCallback); - }); - } else { - securityManager.checkAccess(auth.padID, auth.sessionID, auth.token, auth.password, checkAccessCallback); - } - }, - finalHandler - ]); + /* + * In a previous version of this code, an "if (message)" wrapped the + * following async.series(). + * This ugly "!Boolean(message)" is a lame way to exactly negate the truthy + * condition and replace it with an early return, while being sure to leave + * the original behaviour unchanged. + * + * A shallower code could maybe make more evident latent logic errors. + */ + if (!Boolean(message)) { + return; } + + async.series([ + handleMessageHook, + //check permissions + function(callback) + { + // client tried to auth for the first time (first msg from the client) + if(message.type == "CLIENT_READY") { + createSessionInfo(client, message); + } + + // Note: message.sessionID is an entirely different kind of + // session from the sessions we use here! Beware! + // FIXME: Call our "sessions" "connections". + // FIXME: Use a hook instead + // FIXME: Allow to override readwrite access with readonly + + // Simulate using the load testing tool + if(!sessioninfos[client.id].auth){ + console.error("Auth was never applied to a session. If you are using the stress-test tool then restart Etherpad and the Stress test tool.") + return; + } + + var auth = sessioninfos[client.id].auth; + var checkAccessCallback = function(err, statusObject) + { + if(ERR(err, callback)) return; + + //access was granted + if(statusObject.accessStatus == "grant") + { + callback(); + } + //no access, send the client a message that tell him why + else + { + client.json.send({accessStatus: statusObject.accessStatus}) + } + }; + + //check if pad is requested via readOnly + if (auth.padID.indexOf("r.") === 0) { + //Pad is readOnly, first get the real Pad ID + readOnlyManager.getPadId(auth.padID, function(err, value) { + ERR(err); + securityManager.checkAccess(value, auth.sessionID, auth.token, auth.password, checkAccessCallback); + }); + } else { + securityManager.checkAccess(auth.padID, auth.sessionID, auth.token, auth.password, checkAccessCallback); + } + }, + finalHandler + ]); } From d19436d04494724777adfd829078b0ac66c1781e Mon Sep 17 00:00:00 2001 From: muxator Date: Wed, 29 Aug 2018 01:34:45 +0200 Subject: [PATCH 035/150] adminsettings: early return, no functional changes. --- src/node/hooks/express/adminsettings.js | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/node/hooks/express/adminsettings.js b/src/node/hooks/express/adminsettings.js index 73691837a..baa0bb70a 100644 --- a/src/node/hooks/express/adminsettings.js +++ b/src/node/hooks/express/adminsettings.js @@ -28,15 +28,13 @@ exports.socketio = function (hook_name, args, cb) { if (err) { return console.log(err); } - else - { - //if showSettingsInAdminPage is set to false, then return NOT_ALLOWED in the result - if(settings.showSettingsInAdminPage === false) { - socket.emit("settings", {results:'NOT_ALLOWED'}); - } - else { - socket.emit("settings", {results: data}); - } + + //if showSettingsInAdminPage is set to false, then return NOT_ALLOWED in the result + if(settings.showSettingsInAdminPage === false) { + socket.emit("settings", {results:'NOT_ALLOWED'}); + } + else { + socket.emit("settings", {results: data}); } }); }); From 391bd79e03ea088cee79905d619f985619735d68 Mon Sep 17 00:00:00 2001 From: muxator Date: Wed, 29 Aug 2018 01:38:55 +0200 Subject: [PATCH 036/150] padurlsanitize: early return, no functional changes --- src/node/hooks/express/padurlsanitize.js | 39 ++++++++++++------------ 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/src/node/hooks/express/padurlsanitize.js b/src/node/hooks/express/padurlsanitize.js index a9972220b..be3ffb1b4 100644 --- a/src/node/hooks/express/padurlsanitize.js +++ b/src/node/hooks/express/padurlsanitize.js @@ -8,26 +8,25 @@ exports.expressCreateServer = function (hook_name, args, cb) { if(!padManager.isValidPadId(padId) || /\/$/.test(req.url)) { res.status(404).send('Such a padname is forbidden'); + return; } - else - { - padManager.sanitizePadId(padId, function(sanitizedPadId) { - //the pad id was sanitized, so we redirect to the sanitized version - if(sanitizedPadId != padId) - { - var real_url = sanitizedPadId; - real_url = encodeURIComponent(real_url); - var query = url.parse(req.url).query; - if ( query ) real_url += '?' + query; - res.header('Location', real_url); - res.status(302).send('You should be redirected to ' + real_url + ''); - } - //the pad id was fine, so just render it - else - { - next(); - } - }); - } + + padManager.sanitizePadId(padId, function(sanitizedPadId) { + //the pad id was sanitized, so we redirect to the sanitized version + if(sanitizedPadId != padId) + { + var real_url = sanitizedPadId; + real_url = encodeURIComponent(real_url); + var query = url.parse(req.url).query; + if ( query ) real_url += '?' + query; + res.header('Location', real_url); + res.status(302).send('You should be redirected to ' + real_url + ''); + } + //the pad id was fine, so just render it + else + { + next(); + } + }); }); } From 12f224ae723ac7ba15531f4778732cd220ee5d9f Mon Sep 17 00:00:00 2001 From: muxator Date: Wed, 29 Aug 2018 01:44:13 +0200 Subject: [PATCH 037/150] db/PadManager: early return, no functional changes --- src/node/db/PadManager.js | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/src/node/db/PadManager.js b/src/node/db/PadManager.js index 2ecd6e274..ae908e5c0 100644 --- a/src/node/db/PadManager.js +++ b/src/node/db/PadManager.js @@ -159,21 +159,20 @@ exports.getPad = function(id, text, callback) if(pad != null) { callback(null, pad); + return; } - //try to load pad - else - { - pad = new Pad(id); - //initalize the pad - pad.init(text, function(err) - { - if(ERR(err, callback)) return; - globalPads.set(id, pad); - padList.addPad(id); - callback(null, pad); - }); - } + //try to load pad + pad = new Pad(id); + + //initalize the pad + pad.init(text, function(err) + { + if(ERR(err, callback)) return; + globalPads.set(id, pad); + padList.addPad(id); + callback(null, pad); + }); } exports.listAllPads = function(cb) From ecb0c41d29b9824f1ae592db9d9ed378e92aa747 Mon Sep 17 00:00:00 2001 From: muxator Date: Wed, 29 Aug 2018 01:46:18 +0200 Subject: [PATCH 038/150] db/PadManager: early return, no functional changes --- src/node/db/PadManager.js | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/src/node/db/PadManager.js b/src/node/db/PadManager.js index ae908e5c0..12fa227a3 100644 --- a/src/node/db/PadManager.js +++ b/src/node/db/PadManager.js @@ -205,30 +205,29 @@ exports.sanitizePadId = function(padId, callback) { if(transform_index >= padIdTransforms.length) { callback(padId); + return; } + //check if padId exists - else + exports.doesPadExists(padId, function(junk, exists) { - exports.doesPadExists(padId, function(junk, exists) + if(exists) { - if(exists) + callback(padId); + } + else + { + //get the next transformation *that's different* + var transformedPadId = padId; + while(transformedPadId == padId && transform_index < padIdTransforms.length) { - callback(padId); + transformedPadId = padId.replace(padIdTransforms[transform_index][0], padIdTransforms[transform_index][1]); + transform_index += 1; } - else - { - //get the next transformation *that's different* - var transformedPadId = padId; - while(transformedPadId == padId && transform_index < padIdTransforms.length) - { - transformedPadId = padId.replace(padIdTransforms[transform_index][0], padIdTransforms[transform_index][1]); - transform_index += 1; - } - //check the next transform - exports.sanitizePadId(transformedPadId, callback, transform_index); - } - }); - } + //check the next transform + exports.sanitizePadId(transformedPadId, callback, transform_index); + } + }); } exports.isValidPadId = function(padId) From 4728736dd8283f2a26a66405dea5da1151436752 Mon Sep 17 00:00:00 2001 From: muxator Date: Wed, 29 Aug 2018 01:47:38 +0200 Subject: [PATCH 039/150] db/PadManager: early return, no functional changes --- src/node/db/PadManager.js | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/node/db/PadManager.js b/src/node/db/PadManager.js index 12fa227a3..035ef3e5e 100644 --- a/src/node/db/PadManager.js +++ b/src/node/db/PadManager.js @@ -214,19 +214,18 @@ exports.sanitizePadId = function(padId, callback) { if(exists) { callback(padId); + return; } - else + + //get the next transformation *that's different* + var transformedPadId = padId; + while(transformedPadId == padId && transform_index < padIdTransforms.length) { - //get the next transformation *that's different* - var transformedPadId = padId; - while(transformedPadId == padId && transform_index < padIdTransforms.length) - { - transformedPadId = padId.replace(padIdTransforms[transform_index][0], padIdTransforms[transform_index][1]); - transform_index += 1; - } - //check the next transform - exports.sanitizePadId(transformedPadId, callback, transform_index); + transformedPadId = padId.replace(padIdTransforms[transform_index][0], padIdTransforms[transform_index][1]); + transform_index += 1; } + //check the next transform + exports.sanitizePadId(transformedPadId, callback, transform_index); }); } From 30d814d8ed9d455560251fd8492d4e8880a27d20 Mon Sep 17 00:00:00 2001 From: muxator Date: Wed, 29 Aug 2018 01:57:28 +0200 Subject: [PATCH 040/150] db/API.js: early return, no functional changes --- src/node/db/API.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/node/db/API.js b/src/node/db/API.js index be3e73486..8c8e515cd 100644 --- a/src/node/db/API.js +++ b/src/node/db/API.js @@ -184,17 +184,17 @@ exports.getRevisionChangeset = function(padID, rev, callback) callback(null, changeset); }) - } - //the client wants the latest changeset, lets return it to him - else - { - pad.getRevisionChangeset(pad.getHeadRevisionNumber(), function(err, changeset) - { - if(ERR(err, callback)) return; - callback(null, changeset); - }) + return; } + + //the client wants the latest changeset, lets return it to him + pad.getRevisionChangeset(pad.getHeadRevisionNumber(), function(err, changeset) + { + if(ERR(err, callback)) return; + + callback(null, changeset); + }) }); } From 1d45a63864a7d1a7f71f5541b003de522873a6ab Mon Sep 17 00:00:00 2001 From: muxator Date: Wed, 29 Aug 2018 01:57:00 +0200 Subject: [PATCH 041/150] db/API.js: early return, no functional changes --- src/node/db/API.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/node/db/API.js b/src/node/db/API.js index 8c8e515cd..7c6b95117 100644 --- a/src/node/db/API.js +++ b/src/node/db/API.js @@ -268,13 +268,13 @@ exports.getText = function(padID, rev, callback) callback(null, data); }) + + return; } + //the client wants the latest text, lets return it to him - else - { - var padText = exportTxt.getTXTFromAtext(pad, pad.atext); - callback(null, {"text": padText}); - } + var padText = exportTxt.getTXTFromAtext(pad, pad.atext); + callback(null, {"text": padText}); }); } From 05a33f15331bac551010585c0890a40e6421771f Mon Sep 17 00:00:00 2001 From: muxator Date: Wed, 29 Aug 2018 02:08:05 +0200 Subject: [PATCH 042/150] db/API.js, SessionManager: lot of copied & pasted code in integer parsing Replaced with an early return, no functional changes. --- src/node/db/API.js | 56 +++++++++++++---------------------- src/node/db/SessionManager.js | 8 ++--- 2 files changed, 24 insertions(+), 40 deletions(-) diff --git a/src/node/db/API.js b/src/node/db/API.js index 7c6b95117..c420b9994 100644 --- a/src/node/db/API.js +++ b/src/node/db/API.js @@ -137,15 +137,13 @@ exports.getRevisionChangeset = function(padID, rev, callback) if (rev !== undefined && typeof rev !== "number") { // try to parse the number - if (!isNaN(parseInt(rev))) - { - rev = parseInt(rev); - } - else + if (isNaN(parseInt(rev))) { callback(new customError("rev is not a number", "apierror")); return; } + + rev = parseInt(rev); } // ensure this is not a negative number @@ -219,15 +217,13 @@ exports.getText = function(padID, rev, callback) if(rev !== undefined && typeof rev != "number") { //try to parse the number - if(!isNaN(parseInt(rev))) - { - rev = parseInt(rev); - } - else + if(isNaN(parseInt(rev))) { callback(new customError("rev is not a number", "apierror")); return; } + + rev = parseInt(rev); } //ensure this is not a negativ number @@ -359,15 +355,13 @@ exports.getHTML = function(padID, rev, callback) if (rev !== undefined && typeof rev != "number") { - if (!isNaN(parseInt(rev))) - { - rev = parseInt(rev); - } - else + if (isNaN(parseInt(rev))) { callback(new customError("rev is not a number","apierror")); return; } + + rev = parseInt(rev); } if(rev !== undefined && rev < 0) @@ -641,15 +635,13 @@ exports.saveRevision = function(padID, rev, callback) if(rev !== undefined && typeof rev != "number") { //try to parse the number - if(!isNaN(parseInt(rev))) - { - rev = parseInt(rev); - } - else + if(isNaN(parseInt(rev))) { callback(new customError("rev is not a number", "apierror")); return; } + + rev = parseInt(rev); } //ensure this is not a negativ number @@ -782,15 +774,13 @@ exports.restoreRevision = function (padID, rev, callback) if (rev !== undefined && typeof rev != "number") { //try to parse the number - if (!isNaN(parseInt(rev))) - { - rev = parseInt(rev); - } - else + if (isNaN(parseInt(rev))) { callback(new customError("rev is not a number", "apierror")); return; } + + rev = parseInt(rev); } //ensure this is not a negativ number @@ -1177,30 +1167,26 @@ exports.createDiffHTML = function(padID, startRev, endRev, callback){ if(startRev !== undefined && typeof startRev != "number") { //try to parse the number - if(!isNaN(parseInt(startRev))) - { - startRev = parseInt(startRev, 10); - } - else + if(isNaN(parseInt(startRev))) { callback({stop: "startRev is not a number"}); return; } + + startRev = parseInt(startRev, 10); } //check if rev is a number if(endRev !== undefined && typeof endRev != "number") { //try to parse the number - if(!isNaN(parseInt(endRev))) - { - endRev = parseInt(endRev, 10); - } - else + if(isNaN(parseInt(endRev))) { callback({stop: "endRev is not a number"}); return; } + + endRev = parseInt(endRev, 10); } //get the pad diff --git a/src/node/db/SessionManager.js b/src/node/db/SessionManager.js index 518c70c7a..954203758 100644 --- a/src/node/db/SessionManager.js +++ b/src/node/db/SessionManager.js @@ -90,15 +90,13 @@ exports.createSession = function(groupID, authorID, validUntil, callback) if(typeof validUntil != "number") { //try to parse the number - if(!isNaN(parseInt(validUntil))) - { - validUntil = parseInt(validUntil); - } - else + if(isNaN(parseInt(validUntil))) { callback(new customError("validUntil is not a number","apierror")); return; } + + validUntil = parseInt(validUntil); } //ensure this is not a negativ number From 42bc0a59e13d333eb5d0f462cec82173f2ccd5fb Mon Sep 17 00:00:00 2001 From: muxator Date: Wed, 29 Aug 2018 02:09:33 +0200 Subject: [PATCH 043/150] db/API.js: early return, no functional changes --- src/node/db/API.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/node/db/API.js b/src/node/db/API.js index c420b9994..b47c860fe 100644 --- a/src/node/db/API.js +++ b/src/node/db/API.js @@ -442,11 +442,10 @@ exports.setHTML = function(padID, html, callback) if(e){ callback(new customError("HTML is malformed","apierror")); return; - }else{ - //update the clients on the pad - padMessageHandler.updatePadClients(pad, callback); - return; } + + //update the clients on the pad + padMessageHandler.updatePadClients(pad, callback); }); }); } From fef57efd463a329199831a7bd8976325e255b2d6 Mon Sep 17 00:00:00 2001 From: muxator Date: Wed, 29 Aug 2018 02:10:45 +0200 Subject: [PATCH 044/150] db/API.js: early return, no functional changes --- src/node/db/API.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/node/db/API.js b/src/node/db/API.js index b47c860fe..f477b0e9c 100644 --- a/src/node/db/API.js +++ b/src/node/db/API.js @@ -1116,9 +1116,9 @@ exports.sendClientsMessage = function (padID, msg, callback) { getPadSafe(padID, true, function (err, pad) { if (ERR(err, callback)) { return; - } else { - padMessageHandler.handleCustomMessage(padID, msg, callback); } + + padMessageHandler.handleCustomMessage(padID, msg, callback); } ); } From 610a6db8c8c379beca9cdb11cb197c17bb744595 Mon Sep 17 00:00:00 2001 From: muxator Date: Wed, 29 Aug 2018 02:13:06 +0200 Subject: [PATCH 045/150] db/API.js: early return, no functional changes --- src/node/db/API.js | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/node/db/API.js b/src/node/db/API.js index f477b0e9c..fa1fd3056 100644 --- a/src/node/db/API.js +++ b/src/node/db/API.js @@ -399,19 +399,19 @@ exports.getHTML = function(padID, rev, callback) var data = {html: html}; callback(null, data); }); + + return; } + //the client wants the latest text, lets return it to him - else + exportHtml.getPadHTML(pad, undefined, function (err, html) { - exportHtml.getPadHTML(pad, undefined, function (err, html) - { - if(ERR(err, callback)) return; - html = "" +html; // adds HTML head - html += ""; - var data = {html: html}; - callback(null, data); - }); - } + if(ERR(err, callback)) return; + html = "" +html; // adds HTML head + html += ""; + var data = {html: html}; + callback(null, data); + }); }); } From 67ce19eddb72f9e611ce466939d3707639f77dcf Mon Sep 17 00:00:00 2001 From: muxator Date: Wed, 29 Aug 2018 02:16:24 +0200 Subject: [PATCH 046/150] db/API.js: removed unuseful else clause, no functional changes --- src/node/db/API.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/node/db/API.js b/src/node/db/API.js index fa1fd3056..d2ff92062 100644 --- a/src/node/db/API.js +++ b/src/node/db/API.js @@ -723,8 +723,9 @@ exports.createPad = function(padID, text, callback) callback(new customError("createPad can't create group pads","apierror")); return; } + //check for url special characters - else if(padID.match(/(\/|\?|&|#)/)) + if(padID.match(/(\/|\?|&|#)/)) { callback(new customError("malformed padID: Remove special characters","apierror")); return; From b59818676ec2f086d064c5b75d6961b8a31dd445 Mon Sep 17 00:00:00 2001 From: muxator Date: Wed, 29 Aug 2018 02:18:32 +0200 Subject: [PATCH 047/150] db/API.js: early return to make error handling evident. No functional changes --- src/node/db/API.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/node/db/API.js b/src/node/db/API.js index d2ff92062..21c958809 100644 --- a/src/node/db/API.js +++ b/src/node/db/API.js @@ -949,11 +949,10 @@ exports.getPadID = function(roID, callback) if(retrievedPadID == null) { callback(new customError("padID does not exist","apierror")); + return; } - else - { - callback(null, {padID: retrievedPadID}); - } + + callback(null, {padID: retrievedPadID}); }); } From 2b8646a855626283758a3e19ccdcd6a9a32f9d17 Mon Sep 17 00:00:00 2001 From: muxator Date: Wed, 29 Aug 2018 02:28:35 +0200 Subject: [PATCH 048/150] db/AuthorManager: early return, no functional changes --- src/node/db/AuthorManager.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/node/db/AuthorManager.js b/src/node/db/AuthorManager.js index 1f2a736be..5f48e19d8 100644 --- a/src/node/db/AuthorManager.js +++ b/src/node/db/AuthorManager.js @@ -104,16 +104,16 @@ function mapAuthorWithDBKey (mapperkey, mapper, callback) //return the author callback(null, author); }); - } - //there is a author with this mapper - else - { - //update the timestamp of this author - db.setSub("globalAuthor:" + author, ["timestamp"], new Date().getTime()); - //return the author - callback(null, {authorID: author}); + return; } + + //there is a author with this mapper + //update the timestamp of this author + db.setSub("globalAuthor:" + author, ["timestamp"], new Date().getTime()); + + //return the author + callback(null, {authorID: author}); }); } From 61823e7689fcdec71a5119a6c246eada9f5ed450 Mon Sep 17 00:00:00 2001 From: muxator Date: Wed, 29 Aug 2018 02:28:40 +0200 Subject: [PATCH 049/150] db/AuthorManager: early return, no functional changes --- src/node/db/AuthorManager.js | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/node/db/AuthorManager.js b/src/node/db/AuthorManager.js index 5f48e19d8..c7ebf47f4 100644 --- a/src/node/db/AuthorManager.js +++ b/src/node/db/AuthorManager.js @@ -209,20 +209,19 @@ exports.listPadsOfAuthor = function (authorID, callback) if(author == null) { callback(new customError("authorID does not exist","apierror")) + return; } + //everything is fine, return the pad IDs - else + var pads = []; + if(author.padIDs != null) { - var pads = []; - if(author.padIDs != null) + for (var padId in author.padIDs) { - for (var padId in author.padIDs) - { - pads.push(padId); - } + pads.push(padId); } - callback(null, {padIDs: pads}); } + callback(null, {padIDs: pads}); }); } From 6af419a88e3c71a84ec425bbbe35c99afcbfc9f5 Mon Sep 17 00:00:00 2001 From: muxator Date: Wed, 29 Aug 2018 02:33:29 +0200 Subject: [PATCH 050/150] SecurityManager.js: early return, no functional changes --- src/node/db/SecurityManager.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/node/db/SecurityManager.js b/src/node/db/SecurityManager.js index 98feafb3a..f930b9618 100644 --- a/src/node/db/SecurityManager.js +++ b/src/node/db/SecurityManager.js @@ -90,13 +90,13 @@ exports.checkAccess = function (padID, sessionCookie, token, password, callback) // grant or deny access, with author of token callback(null, statusObject); }); + + return; } + // user may create new pads - no need to check anything - else - { - // grant access, with author of token - callback(null, statusObject); - } + // grant access, with author of token + callback(null, statusObject); }); //don't continue From c85bcf06140e9cd10f75be29f0395752a6c77a38 Mon Sep 17 00:00:00 2001 From: muxator Date: Wed, 29 Aug 2018 02:36:25 +0200 Subject: [PATCH 051/150] db/GroupManager: move inner function on top. No functional change This is to make easier on the eye the next change. --- src/node/db/GroupManager.js | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/node/db/GroupManager.js b/src/node/db/GroupManager.js index 82c14c39d..44bda74f2 100644 --- a/src/node/db/GroupManager.js +++ b/src/node/db/GroupManager.js @@ -213,7 +213,19 @@ exports.createGroupIfNotExistsFor = function(groupMapper, callback) //try to get a group for this mapper db.get("mapper2group:"+groupMapper, function(err, groupID) { - if(ERR(err, callback)) return; + function createGroupForMapper(cb) { + exports.createGroup(function(err, responseObj) + { + if(ERR(err, cb)) return; + + //create the mapper entry for this group + db.set("mapper2group:"+groupMapper, responseObj.groupID); + + cb(null, responseObj); + }); + } + + if(ERR(err, callback)) return; // there is a group for this mapper if(groupID) { @@ -229,18 +241,6 @@ exports.createGroupIfNotExistsFor = function(groupMapper, callback) else { createGroupForMapper(callback) } - - function createGroupForMapper(cb) { - exports.createGroup(function(err, responseObj) - { - if(ERR(err, cb)) return; - - //create the mapper entry for this group - db.set("mapper2group:"+groupMapper, responseObj.groupID); - - cb(null, responseObj); - }); - } }); } From 604952bc97bc31e1af05cfa08268fd5c0cd89d8c Mon Sep 17 00:00:00 2001 From: muxator Date: Wed, 29 Aug 2018 02:38:09 +0200 Subject: [PATCH 052/150] db/GroupManager: fix indentation This is to make easier on the eye the next change. --- src/node/db/GroupManager.js | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/node/db/GroupManager.js b/src/node/db/GroupManager.js index 44bda74f2..f8255ba36 100644 --- a/src/node/db/GroupManager.js +++ b/src/node/db/GroupManager.js @@ -227,20 +227,20 @@ exports.createGroupIfNotExistsFor = function(groupMapper, callback) if(ERR(err, callback)) return; - // there is a group for this mapper - if(groupID) { - exports.doesGroupExist(groupID, function(err, exists) { - if(ERR(err, callback)) return; - if(exists) return callback(null, {groupID: groupID}); - - // hah, the returned group doesn't exist, let's create one - createGroupForMapper(callback) - }) - } - //there is no group for this mapper, let's create a group - else { - createGroupForMapper(callback) - } + // there is a group for this mapper + if(groupID) { + exports.doesGroupExist(groupID, function(err, exists) { + if(ERR(err, callback)) return; + if(exists) return callback(null, {groupID: groupID}); + + // hah, the returned group doesn't exist, let's create one + createGroupForMapper(callback) + }) + } + //there is no group for this mapper, let's create a group + else { + createGroupForMapper(callback) + } }); } From f7254a47eaa17f0a703de05a6e4f55a2d60d2913 Mon Sep 17 00:00:00 2001 From: muxator Date: Wed, 29 Aug 2018 02:39:05 +0200 Subject: [PATCH 053/150] db/GroupManager: early return, no functional changes --- src/node/db/GroupManager.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/node/db/GroupManager.js b/src/node/db/GroupManager.js index f8255ba36..e65c0dc46 100644 --- a/src/node/db/GroupManager.js +++ b/src/node/db/GroupManager.js @@ -236,11 +236,12 @@ exports.createGroupIfNotExistsFor = function(groupMapper, callback) // hah, the returned group doesn't exist, let's create one createGroupForMapper(callback) }) + + return; } + //there is no group for this mapper, let's create a group - else { - createGroupForMapper(callback) - } + createGroupForMapper(callback) }); } From da8faa1aa90c7b477b20d8d6022bd818d85d0294 Mon Sep 17 00:00:00 2001 From: muxator Date: Wed, 29 Aug 2018 02:40:14 +0200 Subject: [PATCH 054/150] db/GroupManager: early return, no functional changes --- src/node/db/GroupManager.js | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/node/db/GroupManager.js b/src/node/db/GroupManager.js index e65c0dc46..118c044bb 100644 --- a/src/node/db/GroupManager.js +++ b/src/node/db/GroupManager.js @@ -321,19 +321,18 @@ exports.listPads = function(groupID, callback) if(exists == false) { callback(new customError("groupID does not exist","apierror")); + return; } + //group exists, let's get the pads - else + db.getSub("group:" + groupID, ["pads"], function(err, result) { - db.getSub("group:" + groupID, ["pads"], function(err, result) - { - if(ERR(err, callback)) return; - var pads = []; - for ( var padId in result ) { - pads.push(padId); - } - callback(null, {padIDs: pads}); - }); - } + if(ERR(err, callback)) return; + var pads = []; + for ( var padId in result ) { + pads.push(padId); + } + callback(null, {padIDs: pads}); + }); }); } From 9ed7608421c0ea242be5955fd253a1e1d7c482b3 Mon Sep 17 00:00:00 2001 From: muxator Date: Wed, 29 Aug 2018 02:41:14 +0200 Subject: [PATCH 055/150] db/GroupManager: early return, no functional changes --- src/node/db/GroupManager.js | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/node/db/GroupManager.js b/src/node/db/GroupManager.js index 118c044bb..c80d8c06e 100644 --- a/src/node/db/GroupManager.js +++ b/src/node/db/GroupManager.js @@ -62,13 +62,12 @@ exports.deleteGroup = function(groupID, callback) if(_group == null) { callback(new customError("groupID does not exist","apierror")); + return; } + //group exists, everything is fine - else - { - group = _group; - callback(); - } + group = _group; + callback(); }); }, //iterate trough all pads of this groups and delete them From a1d21c0cd25f6aa7685785b57169619dfa192ef2 Mon Sep 17 00:00:00 2001 From: muxator Date: Wed, 29 Aug 2018 02:41:53 +0200 Subject: [PATCH 056/150] db/GroupManager: early return, no functional changes --- src/node/db/GroupManager.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/node/db/GroupManager.js b/src/node/db/GroupManager.js index c80d8c06e..741fe6e5a 100644 --- a/src/node/db/GroupManager.js +++ b/src/node/db/GroupManager.js @@ -261,12 +261,11 @@ exports.createGroupPad = function(groupID, padName, text, callback) if(exists == false) { callback(new customError("groupID does not exist","apierror")); + return; } + //group exists, everything is fine - else - { - callback(); - } + callback(); }); }, //ensure pad does not exists From e90487c3e29ec97abfa293ef99e4e366ca8aeba3 Mon Sep 17 00:00:00 2001 From: muxator Date: Wed, 29 Aug 2018 02:42:29 +0200 Subject: [PATCH 057/150] db/GroupManager: early return, no functional changes --- src/node/db/GroupManager.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/node/db/GroupManager.js b/src/node/db/GroupManager.js index 741fe6e5a..0c9be1221 100644 --- a/src/node/db/GroupManager.js +++ b/src/node/db/GroupManager.js @@ -279,12 +279,11 @@ exports.createGroupPad = function(groupID, padName, text, callback) if(exists == true) { callback(new customError("padName does already exist","apierror")); + return; } + //pad does not exist, everything is fine - else - { - callback(); - } + callback(); }); }, //create the pad From 049f5f2859700185e4f94251ba10c1edbf5c0245 Mon Sep 17 00:00:00 2001 From: muxator Date: Wed, 29 Aug 2018 02:44:51 +0200 Subject: [PATCH 058/150] db/Pad: removed unuseful else clause, no functional changes --- src/node/db/Pad.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/node/db/Pad.js b/src/node/db/Pad.js index 0cb01cace..a3920cc8a 100644 --- a/src/node/db/Pad.js +++ b/src/node/db/Pad.js @@ -489,11 +489,9 @@ Pad.prototype.copy = function copy(destinationID, force, callback) { callback(new customError("groupID does not exist for destinationID","apierror")); return; } + //everything is fine, continue - else - { - callback(); - } + callback(); }); } else From 0e8789863c5f2ef83dff941af1f1cf31038e76b9 Mon Sep 17 00:00:00 2001 From: muxator Date: Wed, 29 Aug 2018 02:46:08 +0200 Subject: [PATCH 059/150] db/Pad: removed unuseful else clause, no functional changes --- src/node/db/Pad.js | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/node/db/Pad.js b/src/node/db/Pad.js index a3920cc8a..6386e8b58 100644 --- a/src/node/db/Pad.js +++ b/src/node/db/Pad.js @@ -513,13 +513,12 @@ Pad.prototype.copy = function copy(destinationID, force, callback) { console.error("erroring out without force - after"); return; } - else // exists and forcing - { - padManager.getPad(destinationID, function(err, pad) { - if (ERR(err, callback)) return; - pad.remove(callback); - }); - } + + // exists and forcing + padManager.getPad(destinationID, function(err, pad) { + if (ERR(err, callback)) return; + pad.remove(callback); + }); } else { From d931a700b442eab0b9042e5acf7e7eacee71a493 Mon Sep 17 00:00:00 2001 From: muxator Date: Wed, 29 Aug 2018 02:49:40 +0200 Subject: [PATCH 060/150] db/Pad: reversed condition to make error handling evident. No functional changes Here it was legal to replace a lax comparison with a strict one, since we are using indexOf(), whose return value is known. --- src/node/db/Pad.js | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/src/node/db/Pad.js b/src/node/db/Pad.js index 6386e8b58..f5d65e6ff 100644 --- a/src/node/db/Pad.js +++ b/src/node/db/Pad.js @@ -476,26 +476,27 @@ Pad.prototype.copy = function copy(destinationID, force, callback) { // if it's a group pad, let's make sure the group exists. function(callback) { - if (destinationID.indexOf("$") != -1) + if (destinationID.indexOf("$") === -1) { - destGroupID = destinationID.split("$")[0] - groupManager.doesGroupExist(destGroupID, function (err, exists) - { - if(ERR(err, callback)) return; - - //group does not exist - if(exists == false) - { - callback(new customError("groupID does not exist for destinationID","apierror")); - return; - } - - //everything is fine, continue - callback(); - }); - } - else callback(); + return; + } + + destGroupID = destinationID.split("$")[0] + groupManager.doesGroupExist(destGroupID, function (err, exists) + { + if(ERR(err, callback)) return; + + //group does not exist + if(exists == false) + { + callback(new customError("groupID does not exist for destinationID","apierror")); + return; + } + + //everything is fine, continue + callback(); + }); }, // if the pad exists, we should abort, unless forced. function(callback) From 69e1bf28aa95e23bebc4cc92868b959a70582cb7 Mon Sep 17 00:00:00 2001 From: muxator Date: Wed, 29 Aug 2018 02:52:26 +0200 Subject: [PATCH 061/150] db/Pad: reversed condition to make core logic evident. No functional changes Here it was legal to replace a lax comparison with a strict one, since we are using indexOf(), whose return value is known. --- src/node/db/Pad.js | 39 +++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/src/node/db/Pad.js b/src/node/db/Pad.js index f5d65e6ff..66f9aa598 100644 --- a/src/node/db/Pad.js +++ b/src/node/db/Pad.js @@ -620,29 +620,28 @@ Pad.prototype.remove = function remove(callback) { //is it a group pad? -> delete the entry of this pad in the group function(callback) { - //is it a group pad? - if(padID.indexOf("$")!=-1) - { - var groupID = padID.substring(0,padID.indexOf("$")); - - db.get("group:" + groupID, function (err, group) - { - if(ERR(err, callback)) return; - - //remove the pad entry - delete group.pads[padID]; - - //set the new value - db.set("group:" + groupID, group); - - callback(); - }); - } - //its no group pad, nothing to do here - else + if(padID.indexOf("$") === -1) { + // it isn't a group pad, nothing to do here callback(); + return; } + + // it is a group pad + var groupID = padID.substring(0,padID.indexOf("$")); + + db.get("group:" + groupID, function (err, group) + { + if(ERR(err, callback)) return; + + //remove the pad entry + delete group.pads[padID]; + + //set the new value + db.set("group:" + groupID, group); + + callback(); + }); }, //remove the readonly entries function(callback) From 1a93ab4eb53557e0d67306f71ce7985593092647 Mon Sep 17 00:00:00 2001 From: muxator Date: Wed, 29 Aug 2018 03:03:34 +0200 Subject: [PATCH 062/150] db/Pad: reversed truthy condition to make core logic evident Since the original comparison compared for truthy and not for "===", and it's 3 AM now, I blindly negated it, in order to show how fragile it was in the first instance. No functional changes. This is the final commit of this refactoring series. --- src/node/db/Pad.js | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/src/node/db/Pad.js b/src/node/db/Pad.js index 66f9aa598..91ab7f792 100644 --- a/src/node/db/Pad.js +++ b/src/node/db/Pad.js @@ -505,26 +505,29 @@ Pad.prototype.copy = function copy(destinationID, force, callback) { { if(ERR(err, callback)) return; - if(exists == true) - { - if (!force) - { - console.error("erroring out without force"); - callback(new customError("destinationID already exists","apierror")); - console.error("erroring out without force - after"); - return; - } - - // exists and forcing - padManager.getPad(destinationID, function(err, pad) { - if (ERR(err, callback)) return; - pad.remove(callback); - }); - } - else + /* + * this is the negation of a truthy comparison. Has been left in this + * wonky state to keep the old (possibly buggy) behaviour + */ + if (!(exists == true)) { callback(); + return; } + + if (!force) + { + console.error("erroring out without force"); + callback(new customError("destinationID already exists","apierror")); + console.error("erroring out without force - after"); + return; + } + + // exists and forcing + padManager.getPad(destinationID, function(err, pad) { + if (ERR(err, callback)) return; + pad.remove(callback); + }); }); }, // copy the 'pad' entry From c09e638fc324f266f61fad453daca0b72f91889f Mon Sep 17 00:00:00 2001 From: muxator Date: Wed, 29 Aug 2018 21:45:33 +0200 Subject: [PATCH 063/150] installDeps.sh: don't nuke all installed plugins on update This is a modification of PR #3474 by rohieb . When this script is run after an update, and something fails during the npm run, the installed plugins were deleted, too. In this version what gets deleted is only the directory that contains the direct dependencies of the core Etherpad, ie: node_modules/ep_etherpad-lite/node_modules --- bin/installDeps.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/installDeps.sh b/bin/installDeps.sh index dd7052390..b86e7aa98 100755 --- a/bin/installDeps.sh +++ b/bin/installDeps.sh @@ -116,7 +116,7 @@ echo "Ensure that all dependencies are up to date... If this is the first time cd ep_etherpad-lite npm install --no-save --loglevel warn ) || { - rm -rf node_modules + rm -rf src/node_modules exit 1 } From 8b7f7d49c000891c5f9f18cd287e3d961f9c246f Mon Sep 17 00:00:00 2001 From: Luiza Pagliari Date: Sat, 1 Sep 2018 17:53:46 -0300 Subject: [PATCH 064/150] tests: make sure author is switched on authorship test Original implementation of authorship test assumed a simple pad reload would switch the author -- and it actually did on Chrome. But other browsers might keep the author id on cookie. To force the author switch, expire the cookie before reloading the pad. Fixes: #3435 --- tests/frontend/specs/authorship_of_editions.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/frontend/specs/authorship_of_editions.js b/tests/frontend/specs/authorship_of_editions.js index 3bea2c46e..0c173e962 100644 --- a/tests/frontend/specs/authorship_of_editions.js +++ b/tests/frontend/specs/authorship_of_editions.js @@ -41,6 +41,10 @@ describe('author of pad edition', function() { // Reload pad, to make changes as a second user. Need a timeout here to make sure // all changes were saved before reloading setTimeout(function() { + // Expire cookie, so author is changed after reloading the pad. + // See https://developer.mozilla.org/en-US/docs/Web/API/Document/cookie#Example_4_Reset_the_previous_cookie + helper.padChrome$.document.cookie = 'token=foo;expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/'; + helper.newPad(done, padId); }, 1000); }); From 4a514706cb7080965dfbbf4eb9dc6dd55c169c27 Mon Sep 17 00:00:00 2001 From: "translatewiki.net" Date: Mon, 3 Sep 2018 08:10:53 +0200 Subject: [PATCH 065/150] Localisation updates from https://translatewiki.net. --- src/locales/ml.json | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/locales/ml.json b/src/locales/ml.json index 7d6dd66b9..7c843247c 100644 --- a/src/locales/ml.json +++ b/src/locales/ml.json @@ -7,7 +7,8 @@ "Praveenp", "Santhosh.thottingal", "Nesi", - "Jinoytommanjaly" + "Jinoytommanjaly", + "Ambadyanands" ] }, "index.newPad": "പുതിയ പാഡ്", @@ -22,7 +23,7 @@ "pad.toolbar.unindent.title": "ഇടത്തേക്ക് തള്ളുക (ഷിഫ്റ്റ്+ടാബ്)", "pad.toolbar.undo.title": "തിരസ്കരിക്കുക (Ctrl-Z)", "pad.toolbar.redo.title": "വീണ്ടും ചെയ്യുക (Ctrl-Y)", - "pad.toolbar.clearAuthorship.title": "രചയിതാക്കൾക്കുള്ള നിറം കളയുക (Ctrl+Shift+C)", + "pad.toolbar.clearAuthorship.title": "രചയിതാക്കൾക്കുള്ള നിറങ്ങൾ കളയുക (Ctrl+Shift+C)", "pad.toolbar.import_export.title": "വ്യത്യസ്ത ഫയൽ തരങ്ങളിലേക്ക്/തരങ്ങളിൽ നിന്ന് ഇറക്കുമതി/കയറ്റുമതി ചെയ്യുക", "pad.toolbar.timeslider.title": "സമയരേഖ", "pad.toolbar.savedRevision.title": "നാൾപ്പതിപ്പ് സേവ് ചെയ്യുക", @@ -58,10 +59,11 @@ "pad.importExport.exportword": "മൈക്രോസോഫ്റ്റ് വേഡ്", "pad.importExport.exportpdf": "പി.ഡി.എഫ്.", "pad.importExport.exportopen": "ഒ.ഡി.എഫ്. (ഓപ്പൺ ഡോക്യുമെന്റ് ഫോർമാറ്റ്)", - "pad.importExport.abiword.innerHTML": "പ്ലെയിൻ ടെക്സ്റ്റോ എച്ച്.റ്റി.എം.എൽ. തരമോ മാത്രമേ താങ്കൾക്ക് ഇറക്കുമതി ചെയ്യാനാവൂ. കൂടുതൽ വിപുലീകൃത ഇറക്കുമതി സൗകര്യങ്ങൾക്കായി ദയവായി അബിവേഡ് ഇൻസ്റ്റോൾ ചെയ്യുക.", + "pad.importExport.abiword.innerHTML": "പ്ലെയിൻ ടെക്സ്റ്റോ എച്ച്.റ്റി.എം.എൽ. തരമോ മാത്രമേ താങ്കൾക്ക് ഇറക്കുമതി ചെയ്യാനാവൂ. കൂടുതൽ വിപുലീകൃത ഇറക്കുമതി സൗകര്യങ്ങൾക്കായി ദയവായി അബിവേഡ് ഇൻസ്റ്റോൾ ചെയ്യുക.", "pad.modals.connected": "ബന്ധിപ്പിച്ചിരിക്കുന്നു.", "pad.modals.reconnecting": "താങ്കളുടെ പാഡിലേയ്ക്ക് വീണ്ടും ബന്ധിപ്പിക്കുന്നു...", "pad.modals.forcereconnect": "എന്തായാലും ബന്ധിപ്പിക്കുക", + "pad.modals.reconnecttimer": "വീണ്ടും ബന്ധപ്പെടുവാൻ ശ്രമിക്കുന്നു", "pad.modals.cancel": "റദ്ദാക്കുക", "pad.modals.userdup": "മറ്റൊരു ജാലകത്തിൽ തുറന്നിരിക്കുന്നു", "pad.modals.userdup.explanation": "ഈ കമ്പ്യൂട്ടറിൽ ഈ പാഡ് ഒന്നിലധികം ബ്രൗസർ ജാലകങ്ങളിൽ തുറന്നതായി കാണുന്നു.", @@ -99,6 +101,7 @@ "timeslider.exportCurrent": "ഈ പതിപ്പ് ഇങ്ങനെ എടുക്കുക:", "timeslider.version": "പതിപ്പ് {{version}}", "timeslider.saved": "സേവ് ചെയ്തത് {{month}} {{day}}, {{year}}", + "timeslider.playPause": "പാ‍ഡിലെ ഉള്ളടക്കങ്ങൾ പ്ലേ / പോസ് ചെയ്യുക", "timeslider.backRevision": "ഈ പാഡിലെ ഒരു നാൾപ്പതിപ്പിലേക്ക് മടങ്ങുക", "timeslider.forwardRevision": "ഈ പാഡിലെ അടുത്ത മാറ്റത്തിലേക്ക് പോവുക", "timeslider.dateformat": "{{month}}/{{day}}/{{year}} {{hours}}:{{minutes}}:{{seconds}}", From 1fce593779ab36eb6ca3348f66f0ac3b8e8bcc08 Mon Sep 17 00:00:00 2001 From: "translatewiki.net" Date: Thu, 6 Sep 2018 21:23:58 +0200 Subject: [PATCH 066/150] Localisation updates from https://translatewiki.net. --- src/locales/nah.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/locales/nah.json b/src/locales/nah.json index 262766b33..b9e2ac5c6 100644 --- a/src/locales/nah.json +++ b/src/locales/nah.json @@ -15,7 +15,7 @@ "pad.toolbar.redo.title": "Occeppa (Ctrl+Y)", "pad.toolbar.settings.title": "Tlatlālīliztli", "pad.colorpicker.save": "Xicpiya", - "pad.colorpicker.cancel": "Xiccāhua", + "pad.colorpicker.cancel": "Moxitiniz", "pad.settings.padSettings": "Pad Ītlatlālīliz", "pad.settings.myView": "Notlachiyaliz", "pad.settings.language": "Tlahtōlli:", @@ -24,6 +24,7 @@ "pad.importExport.exportword": "Microsoft Word", "pad.importExport.exportpdf": "PDF", "pad.importExport.exportopen": "ODF (Open Document Format)", + "pad.modals.cancel": "Moxitiniz", "pad.modals.deleted": "Omopohpoloh.", "pad.modals.deleted.explanation": "Ōmopoloh inīn Pad.", "timeslider.version": "Inīc {{version}} Cuepaliztli", From 051a8765e499e3c557c52f2ca167045086f777b5 Mon Sep 17 00:00:00 2001 From: "translatewiki.net" Date: Thu, 13 Sep 2018 10:54:15 +0200 Subject: [PATCH 067/150] Localisation updates from https://translatewiki.net. --- src/locales/ar.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/locales/ar.json b/src/locales/ar.json index 39ec236ce..0237830f1 100644 --- a/src/locales/ar.json +++ b/src/locales/ar.json @@ -61,7 +61,7 @@ "pad.importExport.exportword": "مايكروسوفت وورد", "pad.importExport.exportpdf": "صيغة المستندات المحمولة", "pad.importExport.exportopen": "ODF (نسق المستند المفتوح)", - "pad.importExport.abiword.innerHTML": "لايمكنك الاستيراد إلا من نص عادي أو من تنسيقات إتش تي إم إل. للحصول على المزيد من ميزات الاستيراد المتقدمة، يرجى تثبيت أبيورد .", + "pad.importExport.abiword.innerHTML": "لا يمكنك الاستيراد إلا من نص عادي أو من تنسيقات HTML. للحصول على المزيد من ميزات الاستيراد المتقدمة، يرجى تثبيت AbiWord.", "pad.modals.connected": "متصل.", "pad.modals.reconnecting": "إعادة الاتصال ببادك", "pad.modals.forcereconnect": "فرض إعادة الاتصال", From 2a5e87cc7da748da94d1169df2a470b6406b65b9 Mon Sep 17 00:00:00 2001 From: "translatewiki.net" Date: Thu, 20 Sep 2018 11:05:16 +0200 Subject: [PATCH 068/150] Localisation updates from https://translatewiki.net. --- src/locales/mnw.json | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 src/locales/mnw.json diff --git a/src/locales/mnw.json b/src/locales/mnw.json new file mode 100644 index 000000000..f67bca897 --- /dev/null +++ b/src/locales/mnw.json @@ -0,0 +1,41 @@ +{ + "@metadata": { + "authors": [ + "Aue Nai" + ] + }, + "index.newPad": "တၞးတၟိ", + "pad.toolbar.bold.title": "လ္စံက် (Ctrl+B)", + "pad.toolbar.italic.title": "ဒစေၚ် (Ctrl+I)", + "pad.toolbar.underline.title": "သက်ပၞောန်သၟဝ် (Ctrl+U)", + "pad.toolbar.strikethrough.title": "ခရက်ပၞောန်လဒေါဝ် (Ctrl+5)", + "pad.colorpicker.save": "ဂိုင်သိပ်", + "pad.colorpicker.cancel": "တးပဲါ", + "pad.loading": "ပတိုန်ဒၟံၚ်", + "pad.wrongPassword": "ကောန်ဍေၚ်မၞးဂှ် ဗၠေတ်မံၚ်", + "pad.settings.language": "အရေဝ်ဘာသာ", + "pad.importExport.import_export": "ပလုပ်/ပတိတ်", + "pad.importExport.importSuccessful": "ဍိုက်ပေၚ်စိုပ်ဒတုဲ", + "pad.importExport.exporthtml": "HTML", + "pad.importExport.exportplain": "လိက်ပလး", + "pad.importExport.exportword": "Microsoft Word", + "pad.importExport.exportpdf": "PDF", + "pad.importExport.exportopen": "ODF (Open Document Format)", + "pad.modals.reconnecttimer": "ဂစာန်မံၚ်သွက်ကလေၚ်ဆက်လုပ်", + "pad.modals.cancel": "တးပဲါ", + "pad.modals.unauth": "အခေါၚ်အဝဵုဟွံမွဲ", + "pad.modals.deleted": "ပလီု", + "pad.modals.deleted.explanation": "တၞးဏအ်ဒးဒုၚ်တးပဲါထောံယျ။", + "pad.modals.disconnected": "မၞးဆက်စၠောံဟွံမွဲမံၚ်ယျ", + "pad.share": "ပါ်ပရအ်တၞးဏအ်ညိ", + "pad.share.readonly": "ဆ အယာံမာတ်ဗှ်ဟေၚ်", + "pad.share.link": "လေန်", + "pad.share.emebdcode": "Embed URL", + "timeslider.pageTitle": "{{appTitle}} Timeslider", + "timeslider.toolbar.returnbutton": "ကလၚ်တၞးတေံ", + "timeslider.toolbar.authors": "ကဝိ", + "timeslider.toolbar.authorsList": "ကဝိ ဟွံမွဲ", + "timeslider.toolbar.exportlink.title": "ပတိတ်", + "timeslider.version": "ဗာရှောန်{{version}}", + "timeslider.saved": "သီဂိုၚ်လဝ် {{ဂိတု}} {{တ္ၚဲ}}, {{သၞာံ}}" +} From 23eab79946e40f92c87371e9cad3ed56d93b3ed2 Mon Sep 17 00:00:00 2001 From: muxator Date: Tue, 2 Oct 2018 21:15:45 +0200 Subject: [PATCH 069/150] pad.html: for each client plugin, add a class to #editorcontainerbox This commit implements the following behaviour: 1. adds a function clientPluginNames() to hooks.js (mimicking what is done in static.js), which returns an array containing the list of currently installed client side plugins. The array is eventually empty. 2. calls that function in pad.html at rendering time (thus server-side) to populate a class attribute. Example results: - with no client-side plugins installed:
- with some client-side plugins installed:
Looking at the existing code (src/node/hooks/express/static.js#L39-L57), a client-side plugin is defined as a plugin that implements at least a client side hook. NOTE: there is currently no support for notifying plugin removal/installation to the connected clients: for now, in order to get an updated class list, the clients will have to refresh the page. Fixes #3488 --- doc/plugins.md | 16 ++++++++++++++++ src/static/js/pluginfw/hooks.js | 26 ++++++++++++++++++++++++++ src/templates/pad.html | 2 +- 3 files changed, 43 insertions(+), 1 deletion(-) diff --git a/doc/plugins.md b/doc/plugins.md index 0dccbe848..ae3ef954a 100644 --- a/doc/plugins.md +++ b/doc/plugins.md @@ -47,6 +47,22 @@ You can omit the `FUNCTIONNAME` part, if the exported function has got the same ### Client hooks and server hooks There are server hooks, which will be executed on the server (e.g. `expressCreateServer`), and there are client hooks, which are executed on the client (e.g. `acePopulateDomLine`). Be sure to not make assumptions about the environment your code is running in, e.g. don't try to access `process`, if you know your code will be run on the client, and likewise, don't try to access `window` on the server... +### Styling +When you install a client-side plugin (e.g. one that implements at least one client-side hook), the plugin name is added to the `class` attribute of the div `#editorcontainerbox` in the main window. +This gives you the opportunity of tuning the appearence of the main UI in your plugin. + +For example, this is the markup with no plugins installed: +```html +
+``` + +and this is the contents after installing `someplugin`: +```html +
+``` + +This feature was introduced in Etherpad **1.8**. + ### Parts As your plugins become more and more complex, you will find yourself in the need to manage dependencies between plugins. E.g. you want the hooks of a certain plugin to be executed before (or after) yours. You can also manage these dependencies in your plugin definition file `ep.json`: diff --git a/src/static/js/pluginfw/hooks.js b/src/static/js/pluginfw/hooks.js index cf5fcc4eb..81f56f965 100644 --- a/src/static/js/pluginfw/hooks.js +++ b/src/static/js/pluginfw/hooks.js @@ -125,3 +125,29 @@ exports.callAllStr = function(hook_name, args, sep, pre, post) { } return newCallhooks.join(sep || ""); } + +/* + * Returns an array containing the names of the installed client-side plugins + * + * If no client-side plugins are installed, returns an empty array. + * Duplicate names are always discarded. + * + * A client-side plugin is a plugin that implements at least one client_hook + * + * EXAMPLE: + * No plugins: [] + * Some plugins: [ 'ep_adminpads', 'ep_add_buttons', 'ep_activepads' ] + */ +exports.clientPluginNames = function() { + if (!(exports.plugins)) { + return []; + } + + var client_plugin_names = [...new Set( + exports.plugins.parts + .filter(part => part.hasOwnProperty('client_hooks')) + .map(part => part['plugin']) + )]; + + return client_plugin_names; +} diff --git a/src/templates/pad.html b/src/templates/pad.html index e2dc89789..a0b401d59 100644 --- a/src/templates/pad.html +++ b/src/templates/pad.html @@ -100,7 +100,7 @@ <% e.end_block(); %>
-
+
From 4121add1b8b2babfb71363b3deeb254c5aa3f05f Mon Sep 17 00:00:00 2001 From: "translatewiki.net" Date: Wed, 3 Oct 2018 22:03:52 +0200 Subject: [PATCH 070/150] Localisation updates from https://translatewiki.net. --- src/locales/mnw.json | 23 ++++++++++++++++++++++- src/locales/sd.json | 5 +++-- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/locales/mnw.json b/src/locales/mnw.json index f67bca897..ae9f18c3c 100644 --- a/src/locales/mnw.json +++ b/src/locales/mnw.json @@ -37,5 +37,26 @@ "timeslider.toolbar.authorsList": "ကဝိ ဟွံမွဲ", "timeslider.toolbar.exportlink.title": "ပတိတ်", "timeslider.version": "ဗာရှောန်{{version}}", - "timeslider.saved": "သီဂိုၚ်လဝ် {{ဂိတု}} {{တ္ၚဲ}}, {{သၞာံ}}" + "timeslider.saved": "သီဂိုၚ်လဝ် {{month}} {{day}}, {{year}}", + "timeslider.month.january": "ဇာန်နဝါရဳ", + "timeslider.month.february": "ဖေဖဝ်ဝါရဳ", + "timeslider.month.march": "မာတ်", + "timeslider.month.april": "ဨပြဳ", + "timeslider.month.may": "မေ", + "timeslider.month.june": "ဂျောန်", + "timeslider.month.july": "ဂျူလာင်", + "timeslider.month.august": "အဝ်ဂေတ်", + "timeslider.month.september": "\nသေပ်တေမ်ပါ", + "timeslider.month.october": "\nအံက်တဝ်ပါ", + "timeslider.month.november": "\nနဝ်ဝေမ်ပါ", + "timeslider.month.december": "ဒဳဇြေန်ပါ", + "timeslider.unnamedauthors": "{{num}} ဟွံကဵုယၟု {[ဂမၠိုၚ်(num) မွဲ: ကဝိ, တၞဟ်: ကဝိဂမၠိုၚ် ]}", + "pad.userlist.entername": "စုတ် ယၟုညးလွပ်", + "pad.userlist.unnamed": "ဟွံကဵုလဝ်ယၟု", + "pad.userlist.guest": "ကၟုဲ", + "pad.userlist.deny": "တးပဲါ", + "pad.userlist.approve": "သ္ပကဵုဒတန်", + "pad.impexp.importbutton": " မပၠောပ်စုတ် လၟုဟ်", + "pad.impexp.importing": "မပၠောပ်စုတ်ဒၟံၚ်...", + "pad.impexp.importfailed": "မပၠောပ်စုတ်တအ်လီုအာ" } diff --git a/src/locales/sd.json b/src/locales/sd.json index bf8a36e57..b16feda82 100644 --- a/src/locales/sd.json +++ b/src/locales/sd.json @@ -1,7 +1,8 @@ { "@metadata": { "authors": [ - "Mehtab ahmed" + "Mehtab ahmed", + "Tweety" ] }, "index.newPad": "نئين پٽي", @@ -37,7 +38,7 @@ "pad.importExport.importSuccessful": "ڪامياب!", "pad.importExport.export": "هاڻوڪي پٽي برآمد ڪريو جي طور:", "pad.importExport.exporthtml": "HTML", - "pad.importExport.exportplain": "سادو متن", + "pad.importExport.exportplain": "سدا اکر", "pad.importExport.exportword": "مائيڪرسافٽ ورڊ", "pad.importExport.exportpdf": "PDF", "pad.importExport.exportopen": "ODF (کليل دستاويز فارميٽ)", From 9aaa02ec703453de3389929f8d806ca2ca2dde52 Mon Sep 17 00:00:00 2001 From: muxator Date: Sat, 6 Oct 2018 02:25:37 +0200 Subject: [PATCH 071/150] installDeps: no need to download jquery at starting time. Remove curl dependency In installDeps.sh we have a bunch of code (from 2011) that checks for the existence of jQuery and eventually downloads it, but since 1239ce7f2848 (year 2012) jquery is vendorized in /src/static/js/jquery.js. Also, stop mentioning curl as a dependency in the README.md Fixes #3494 --- README.md | 8 ++++---- bin/installDeps.sh | 33 --------------------------------- 2 files changed, 4 insertions(+), 37 deletions(-) diff --git a/README.md b/README.md index f8c4f1227..6b6735b5c 100644 --- a/README.md +++ b/README.md @@ -19,10 +19,10 @@ git clone https://github.com/ether/etherpad-lite.git && cd etherpad-lite && bin/ ``` ## GNU/Linux and other UNIX-like systems -You'll need gzip, git, curl, libssl develop libraries, python and gcc. -- *For Debian/Ubuntu*: `apt install gzip git curl python libssl-dev pkg-config build-essential` -- *For Fedora/CentOS*: `yum install gzip git curl python openssl-devel && yum groupinstall "Development Tools"` -- *For FreeBSD*: `portinstall node, npm, curl, git (optional)` +You'll need gzip, git, libssl develop libraries, python and gcc. +- *For Debian/Ubuntu*: `apt install gzip git python libssl-dev pkg-config build-essential` +- *For Fedora/CentOS*: `yum install gzip git python openssl-devel && yum groupinstall "Development Tools"` +- *For FreeBSD*: `portinstall node, npm, git (optional)` Additionally, you'll need [node.js](https://nodejs.org) installed (minimum required Node version: **6.9.0**). Ideally, the latest stable version is preferred. Please note that the packages offered on some operating systems are outdated. In those cases, we recommend installing nodejs from official archives or compiling it from source (avoiding yum/apt). diff --git a/bin/installDeps.sh b/bin/installDeps.sh index b86e7aa98..a56031217 100755 --- a/bin/installDeps.sh +++ b/bin/installDeps.sh @@ -56,20 +56,6 @@ if [ -d "../bin" ]; then cd "../" fi -#Is gnu-grep (ggrep) installed on SunOS (Solaris) -if [ $(uname) = "SunOS" ]; then - hash ggrep > /dev/null 2>&1 || { - echo "Please install ggrep (pkg install gnu-grep)" >&2 - exit 1 - } -fi - -#Is curl installed? -hash curl > /dev/null 2>&1 || { - echo "Please install curl" >&2 - exit 1 -} - #Is node installed? #Not checking io.js, default installation creates a symbolic link to node hash node > /dev/null 2>&1 || { @@ -120,25 +106,6 @@ echo "Ensure that all dependencies are up to date... If this is the first time exit 1 } -echo "Ensure jQuery is downloaded and up to date..." -DOWNLOAD_JQUERY="true" -NEEDED_VERSION="1.9.1" -if [ -f "src/static/js/jquery.js" ]; then - if [ $(uname) = "SunOS" ]; then - VERSION=$(head -n 3 src/static/js/jquery.js | ggrep -o "v[0-9]\.[0-9]\(\.[0-9]\)\?") - else - VERSION=$(head -n 3 src/static/js/jquery.js | grep -o "v[0-9]\.[0-9]\(\.[0-9]\)\?") - fi - - if [ ${VERSION#v} = $NEEDED_VERSION ]; then - DOWNLOAD_JQUERY="false" - fi -fi - -if [ $DOWNLOAD_JQUERY = "true" ]; then - curl -lo src/static/js/jquery.js https://code.jquery.com/jquery-$NEEDED_VERSION.js || exit 1 -fi - #Remove all minified data to force node creating it new echo "Clearing minified cache..." rm -f var/minified* From 4f756d3953724ab11bb47c2e84a69adce02a2600 Mon Sep 17 00:00:00 2001 From: "translatewiki.net" Date: Mon, 15 Oct 2018 09:25:07 +0200 Subject: [PATCH 072/150] Localisation updates from https://translatewiki.net. --- src/locales/es.json | 11 ++++++----- src/locales/ml.json | 6 +++--- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/locales/es.json b/src/locales/es.json index d271b61ea..747ec7bf5 100644 --- a/src/locales/es.json +++ b/src/locales/es.json @@ -13,7 +13,8 @@ "Macofe", "Fitoschido", "Dgstranz", - "Luzcaru" + "Luzcaru", + "Tiberius1701" ] }, "index.newPad": "Nuevo pad", @@ -83,14 +84,14 @@ "pad.modals.slowcommit.explanation": "El servidor no responde.", "pad.modals.slowcommit.cause": "Puede deberse a problemas con tu conexión de red.", "pad.modals.badChangeset.explanation": "Has hecho una edición clasificada como ilegal por el servidor de sincronización.", - "pad.modals.badChangeset.cause": "Esto podría deberse a una mala configuración del servidor o algún otro comportamiento inesperado. Contacta al administrador del servicio, si piensas que esto es un error. Intenta reconectarte con el fin de seguir editando.", + "pad.modals.badChangeset.cause": "Esto podría deberse a una mala configuración del servidor o algún otro comportamiento inesperado. Contacta con administrador del servicio, si piensas que esto es un error. Intenta volver a conectar para continuar editando.", "pad.modals.corruptPad.explanation": "El pad que intentas acceder está dañado.", - "pad.modals.corruptPad.cause": "Esto puede deberse a una mala configuración del servidor o algún otro comportamiento inesperado. Contacta al administrador del servicio.", + "pad.modals.corruptPad.cause": "Esto puede deberse a una mala configuración del servidor o algún otro comportamiento inesperado. Contacta con el administrador del servicio.", "pad.modals.deleted": "Borrado.", "pad.modals.deleted.explanation": "Este pad ha sido borrado.", "pad.modals.disconnected": "Te has desconectado.", "pad.modals.disconnected.explanation": "Se perdió la conexión con el servidor", - "pad.modals.disconnected.cause": "El servidor podría no estar disponible. Contacta al administrador del servicio si esto continúa sucediendo.", + "pad.modals.disconnected.cause": "El servidor podría no estar disponible. Contacta con el administrador del servicio si esto continúa sucediendo.", "pad.share": "Compatir este pad", "pad.share.readonly": "Solo lectura", "pad.share.link": "Enlace", @@ -139,5 +140,5 @@ "pad.impexp.uploadFailed": "El envío falló. Inténtalo de nuevo.", "pad.impexp.importfailed": "Fallo al importar", "pad.impexp.copypaste": "Intenta copiar y pegar", - "pad.impexp.exportdisabled": "La exportación al formato {{type}} está desactivada. Contacta a tu administrador de sistemas." + "pad.impexp.exportdisabled": "La exportación al formato {{type}} está desactivada. Contacta con tu administrador del sistema." } diff --git a/src/locales/ml.json b/src/locales/ml.json index 7c843247c..e6968036e 100644 --- a/src/locales/ml.json +++ b/src/locales/ml.json @@ -13,9 +13,9 @@ }, "index.newPad": "പുതിയ പാഡ്", "index.createOpenPad": "അല്ലെങ്കിൽ പേരുപയോഗിച്ച് പാഡ് സൃഷ്ടിക്കുക/തുറക്കുക:", - "pad.toolbar.bold.title": "കടുപ്പത്തിലെഴുതുക (Ctrl-B)", - "pad.toolbar.italic.title": "ചെരിച്ചെഴുതുക (Ctrl-I)", - "pad.toolbar.underline.title": "അടിവരയിടുക (Ctrl-U)", + "pad.toolbar.bold.title": "കടുപ്പത്തിലെഴുതുക (Ctrl+B)", + "pad.toolbar.italic.title": "ചെരിച്ചെഴുതുക (Ctrl+I)", + "pad.toolbar.underline.title": "അടിവരയിടുക (Ctrl+U)", "pad.toolbar.strikethrough.title": "വെട്ടുക (Ctrl+5)", "pad.toolbar.ol.title": "ക്രമത്തിലുള്ള പട്ടിക (Ctrl+Shift+N)", "pad.toolbar.ul.title": "ക്രമരഹിത പട്ടിക (Ctrl+Shift+L)", From 5734eea10b8e09da02b0af1a2013484320594d13 Mon Sep 17 00:00:00 2001 From: muxator Date: Wed, 17 Oct 2018 00:26:51 +0200 Subject: [PATCH 073/150] dependencies: update express, 4.16.3 -> 4.16.4 --- src/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/package.json b/src/package.json index bbb069201..86e9a2258 100644 --- a/src/package.json +++ b/src/package.json @@ -36,7 +36,7 @@ "ejs": "2.5.7", "etherpad-require-kernel": "1.0.9", "etherpad-yajsml": "0.0.2", - "express": "4.16.3", + "express": "4.16.4", "express-session": "1.15.6", "find-root": "1.1.0", "formidable": "1.2.1", From c69c0053b60b990a8832575439814ff11cf55551 Mon Sep 17 00:00:00 2001 From: muxator Date: Wed, 17 Oct 2018 00:27:25 +0200 Subject: [PATCH 074/150] dependencies: update npm, 6.4.0 -> 6.4.1 --- src/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/package.json b/src/package.json index 86e9a2258..0a8cb7683 100644 --- a/src/package.json +++ b/src/package.json @@ -45,7 +45,7 @@ "languages4translatewiki": "0.1.3", "log4js": "0.6.35", "measured-core": "1.11.2", - "npm": "6.4.0", + "npm": "6.4.1", "object.values": "^1.0.4", "request": "2.83.0", "resolve": "1.1.7", From 50b245d26073d67ce42c71f1b475d46ddd688b5d Mon Sep 17 00:00:00 2001 From: muxator Date: Wed, 17 Oct 2018 00:27:51 +0200 Subject: [PATCH 075/150] dependencies: update request, 2.83.0 -> 2.88.0 --- src/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/package.json b/src/package.json index 0a8cb7683..c4ffb04f3 100644 --- a/src/package.json +++ b/src/package.json @@ -47,7 +47,7 @@ "measured-core": "1.11.2", "npm": "6.4.1", "object.values": "^1.0.4", - "request": "2.83.0", + "request": "2.88.0", "resolve": "1.1.7", "security": "1.0.0", "semver": "5.1.0", From a585487802cac7c67bcb724d2f6d4c8dd0b05a4a Mon Sep 17 00:00:00 2001 From: muxator Date: Wed, 17 Oct 2018 00:28:21 +0200 Subject: [PATCH 076/150] dependencies: update semver, 5.1.0 -> 5.6.0 --- src/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/package.json b/src/package.json index c4ffb04f3..47df2efa3 100644 --- a/src/package.json +++ b/src/package.json @@ -50,7 +50,7 @@ "request": "2.88.0", "resolve": "1.1.7", "security": "1.0.0", - "semver": "5.1.0", + "semver": "5.6.0", "slide": "1.1.6", "socket.io": "2.1.1", "swagger-node-express": "2.1.3", From f67fc3ad38635ec78824cb56997f2044f79b2aaa Mon Sep 17 00:00:00 2001 From: muxator Date: Wed, 17 Oct 2018 00:31:55 +0200 Subject: [PATCH 077/150] dependencies: update ejs, 2.5.7 -> 2.6.1 --- src/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/package.json b/src/package.json index 47df2efa3..a8c8c6787 100644 --- a/src/package.json +++ b/src/package.json @@ -33,7 +33,7 @@ "cheerio": "0.20.0", "clean-css": "3.4.19", "cookie-parser": "1.3.4", - "ejs": "2.5.7", + "ejs": "2.6.1", "etherpad-require-kernel": "1.0.9", "etherpad-yajsml": "0.0.2", "express": "4.16.4", From e68edcd23d734c5d7f0fcfbddd3516efac4cd6f7 Mon Sep 17 00:00:00 2001 From: muxator Date: Wed, 17 Oct 2018 00:34:28 +0200 Subject: [PATCH 078/150] dependencies: update cookie-parser, 1.3.4 -> 1.4.3 --- src/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/package.json b/src/package.json index a8c8c6787..8c96e690b 100644 --- a/src/package.json +++ b/src/package.json @@ -32,7 +32,7 @@ "channels": "0.0.4", "cheerio": "0.20.0", "clean-css": "3.4.19", - "cookie-parser": "1.3.4", + "cookie-parser": "1.4.3", "ejs": "2.6.1", "etherpad-require-kernel": "1.0.9", "etherpad-yajsml": "0.0.2", From 9774518525fe193f83f009c8e46ab11fee0874eb Mon Sep 17 00:00:00 2001 From: muxator Date: Wed, 17 Oct 2018 00:37:35 +0200 Subject: [PATCH 079/150] dependencies: update graceful-fs, 4.1.3 -> 4.1.11 --- src/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/package.json b/src/package.json index 8c96e690b..a9dd839f8 100644 --- a/src/package.json +++ b/src/package.json @@ -40,7 +40,7 @@ "express-session": "1.15.6", "find-root": "1.1.0", "formidable": "1.2.1", - "graceful-fs": "4.1.3", + "graceful-fs": "4.1.11", "jsonminify": "0.4.1", "languages4translatewiki": "0.1.3", "log4js": "0.6.35", From 20be994d9b6d57dd8a234b7bd32fafe8f81cb9eb Mon Sep 17 00:00:00 2001 From: "translatewiki.net" Date: Thu, 18 Oct 2018 08:18:00 +0200 Subject: [PATCH 080/150] Localisation updates from https://translatewiki.net. --- src/locales/bg.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/locales/bg.json b/src/locales/bg.json index 52e424c37..0b29b0e77 100644 --- a/src/locales/bg.json +++ b/src/locales/bg.json @@ -19,7 +19,7 @@ "pad.toolbar.redo.title": "Връщане (Ctrl+Y)", "pad.toolbar.settings.title": "Настройки", "pad.colorpicker.save": "Съхраняване", - "pad.colorpicker.cancel": "Отказване", + "pad.colorpicker.cancel": "Отказ", "pad.loading": "Зареждане...", "pad.wrongPassword": "Неправилна парола", "pad.settings.language": "Език:", @@ -29,7 +29,7 @@ "pad.importExport.exportword": "Microsoft Word", "pad.importExport.exportpdf": "PDF", "pad.importExport.exportopen": "ODF (Open Document Format)", - "pad.modals.cancel": "Отказване", + "pad.modals.cancel": "Отказ", "pad.modals.userdup": "Отворен в друг прозорец", "pad.modals.userdup.explanation": "Изглежда, че този пад е отворен на повече от един раздел в браузъра на компютъра.", "pad.modals.looping.explanation": "Има проблеми с комуникацията със сървъра за синхронизация.", From f6cef9dfd2fff94086c1b45ca69fcf411400c091 Mon Sep 17 00:00:00 2001 From: muxator Date: Mon, 29 Oct 2018 21:46:19 +0100 Subject: [PATCH 081/150] skins: fix timeslider support Found by Sebastian Castro <90scastro@gmail.com> This was really meant to be part of 9c990ab08a51 --- src/templates/timeslider.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/templates/timeslider.html b/src/templates/timeslider.html index 395d0c478..5aee24c7a 100644 --- a/src/templates/timeslider.html +++ b/src/templates/timeslider.html @@ -36,7 +36,7 @@ <% e.begin_block("timesliderStyles"); %> - + <% e.end_block(); %> @@ -227,7 +227,7 @@ - +