diff --git a/.gitignore b/.gitignore index c6ec3f9fb..52d60dca7 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ node_modules settings.json !settings.json.template APIKEY.txt +SESSIONKEY.txt bin/abiword.exe bin/node.exe etherpad-lite-win.zip diff --git a/CHANGELOG.md b/CHANGELOG.md index 926e3d3c9..84d85000d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,19 @@ +# 1.5.6 + * Fix: Error on windows installations + +# 1.5.5 + * SECURITY: Also don't allow read files on directory traversal on minify paths + * NEW: padOptions can be set in settings.json now + * Fix: Add check for special characters in createPad API function + * Fix: Middle click on a link in firefox don't paste text anymore + * Fix: Made setPadRaw async to import larger etherpad files + * Fix: rtl + * Fix: Problem in older IEs + * Other: Update to express 4.x + * Other: Dropped support for node 0.8 + * Other: Update ejs to version 2.x + * Other: Moved sessionKey from settings.json to a new auto-generated SESSIONKEY.txt file + # 1.5.4 * SECURITY: Also don't allow read files on directory traversal on frontend tests path diff --git a/README.md b/README.md index bef84656f..12ea3998a 100644 --- a/README.md +++ b/README.md @@ -92,7 +92,7 @@ Documentation can be found in `docs/`. # Development ## Things you should know -Read this [git guide](http://learn.github.com/p/index.html) and watch this [video on getting started with Etherpad Development](http://youtu.be/67-Q26YH97E). +Understand [git](https://training.github.com/) and watch this [video on getting started with Etherpad Development](http://youtu.be/67-Q26YH97E). If you're new to node.js, start with Ryan Dahl's [Introduction to Node.js](http://youtu.be/jo_B4LTHi3I). diff --git a/bin/buildForWindows.sh b/bin/buildForWindows.sh index 212e946b4..a508cc228 100755 --- a/bin/buildForWindows.sh +++ b/bin/buildForWindows.sh @@ -1,6 +1,6 @@ #!/bin/sh -NODE_VERSION="0.10.38" +NODE_VERSION="0.12.2" #Move to the folder where ep-lite is installed cd `dirname $0` @@ -56,8 +56,6 @@ echo "remove git history to reduce folder size" rm -rf .git/objects echo "remove windows jsdom-nocontextify/test folder" -rm -rf /tmp/etherpad-lite-win/node_modules/ep_etherpad-lite/node_modules/jsdom-nocontextifiy/test/ -rm -rf /tmp/etherpad-lite-win/src/node_modules/jsdom-nocontextifiy/test/ rm -rf /tmp/etherpad-lite-win/src/node_modules/wd/node_modules/request/node_modules/form-data/node_modules/combined-stream/test rm -rf /tmp/etherpad-lite-win/src/node_modules/nodemailer/node_modules/mailcomposer/node_modules/mimelib/node_modules/encoding/node_modules/iconv-lite/encodings/tables diff --git a/doc/api/hooks_server-side.md b/doc/api/hooks_server-side.md index c7e7a43af..717abe75d 100644 --- a/doc/api/hooks_server-side.md +++ b/doc/api/hooks_server-side.md @@ -254,7 +254,7 @@ var Changeset = require("ep_etherpad-lite/static/js/Changeset"); exports.getLineHTMLForExport = function (hook, context) { var header = _analyzeLine(context.attribLine, context.apool); if (header) { - return "<" + header + ">" + context.lineContents + ""; + return "<" + header + ">" + context.lineContent + ""; } } diff --git a/settings.json.template b/settings.json.template index ea7ed1e12..39c383eda 100644 --- a/settings.json.template +++ b/settings.json.template @@ -15,10 +15,6 @@ "ip": "0.0.0.0", "port" : 9001, - // Session Key, used for reconnecting user sessions - // Set this to a secure string at least 10 characters long. Do not share this value. - "sessionKey" : "", - /* // Node native SSL support // this is disabled by default @@ -53,6 +49,21 @@ //the default text of a pad "defaultPadText" : "Welcome to Etherpad!\n\nThis pad text is synchronized as you type, so that everyone viewing this page sees the same text. This allows you to collaborate seamlessly on documents!\n\nGet involved with Etherpad at http:\/\/etherpad.org\n", + + /* Default Pad behavior, users can override by changing */ + "padOptions": { + "noColors": false, + "showControls": true, + "showChat": true, + "showLineNumbers": true, + "useMonospaceFont": false, + "userName": false, + "userColor": false, + "rtl": false, + "alwaysShowChat": false, + "chatAndUsers": false, + "lang": "en-gb" + }, /* Shoud we suppress errors from being visible in the default Pad Text? */ "suppressErrorsInPadText" : false, diff --git a/src/node/handler/ImportHandler.js b/src/node/handler/ImportHandler.js index ba6f4415a..7ad82a87d 100644 --- a/src/node/handler/ImportHandler.js +++ b/src/node/handler/ImportHandler.js @@ -113,10 +113,8 @@ exports.doImport = function(req, res, padId) if(ERR(err, callback)) return callback(); if(result.length > 0){ // This feels hacky and wrong.. importHandledByPlugin = true; - callback(); - }else{ - callback(); } + callback(); }); }, function(callback) { @@ -145,7 +143,7 @@ exports.doImport = function(req, res, padId) }, //convert file to html function(callback) { - if(!importHandledByPlugin || !directDatabaseAccess){ + if(!importHandledByPlugin && !directDatabaseAccess){ var fileEnding = path.extname(srcFile).toLowerCase(); var fileIsHTML = (fileEnding === ".html" || fileEnding === ".htm"); var fileIsTXT = (fileEnding === ".txt"); @@ -171,28 +169,24 @@ exports.doImport = function(req, res, padId) }, function(callback) { - if (!abiword){ - if(!directDatabaseAccess) { - // Read the file with no encoding for raw buffer access. - fs.readFile(destFile, function(err, buf) { - if (err) throw err; - var isAscii = true; - // Check if there are only ascii chars in the uploaded file - for (var i=0, len=buf.length; i 240) { - isAscii=false; - break; - } + if (!abiword && !directDatabaseAccess){ + // Read the file with no encoding for raw buffer access. + fs.readFile(destFile, function(err, buf) { + if (err) throw err; + var isAscii = true; + // Check if there are only ascii chars in the uploaded file + for (var i=0, len=buf.length; i 240) { + isAscii=false; + break; } - if (isAscii) { - callback(); - } else { - callback("uploadFailed"); - } - }); - }else{ - callback(); - } + } + if (isAscii) { + callback(); + } else { + callback("uploadFailed"); + } + }); } else { callback(); } diff --git a/src/node/handler/PadMessageHandler.js b/src/node/handler/PadMessageHandler.js index c210ab2b3..e15af1a46 100644 --- a/src/node/handler/PadMessageHandler.js +++ b/src/node/handler/PadMessageHandler.js @@ -1182,6 +1182,7 @@ function handleClientReady(client, message) "userIsGuest": true, "userColor": authorColorId, "padId": message.padId, + "padOptions": settings.padOptions, "initialTitle": "Pad: " + message.padId, "opts": {}, // tell the client the number of the latest chat-message, which will be diff --git a/src/node/utils/ImportEtherpad.js b/src/node/utils/ImportEtherpad.js index 37863bfff..bf1129cb9 100644 --- a/src/node/utils/ImportEtherpad.js +++ b/src/node/utils/ImportEtherpad.js @@ -21,20 +21,11 @@ var db = require("../db/DB").db; exports.setPadRaw = function(padId, records, callback){ records = JSON.parse(records); - // !! HACK !! - // If you have a really large pad it will cause a Maximum Range Stack crash - // This is a temporary patch for that so things are kept stable. - var recordCount = Object.keys(records).length; - if(recordCount >= 50000){ - console.warn("Etherpad file is too large to import.. We need to fix this. See https://github.com/ether/etherpad-lite/issues/2524"); - return callback("tooLarge", false); - } - async.eachSeries(Object.keys(records), function(key, cb){ var value = records[key] if(!value){ - cb(); // null values are bad. + return setImmediate(cb); } // Author data @@ -76,7 +67,7 @@ exports.setPadRaw = function(padId, records, callback){ // Write the value to the server db.set(newKey, value); - cb(); + setImmediate(cb); }, function(){ callback(null, true); }); diff --git a/src/node/utils/Minify.js b/src/node/utils/Minify.js index 6fe6200af..d7c3f332e 100644 --- a/src/node/utils/Minify.js +++ b/src/node/utils/Minify.js @@ -144,8 +144,11 @@ function minify(req, res, next) // No relative paths, especially if they may go up the file hierarchy. filename = path.normalize(path.join(ROOT_DIR, filename)); + filename = filename.replace(/\.\./g, '') + if (filename.indexOf(ROOT_DIR) == 0) { filename = filename.slice(ROOT_DIR.length); + filename = filename.replace(/\\/g, '/') } else { res.writeHead(404, {}); res.end(); @@ -166,7 +169,7 @@ function minify(req, res, next) var plugin = plugins.plugins[library]; var pluginPath = plugin.package.realPath; filename = path.relative(ROOT_DIR, pluginPath + libraryPath); - filename = filename.replace(/\\/g, '/'); // Windows (safe generally?) + filename = filename.replace(/\\/g, '/'); // windows path fix } else if (LIBRARY_WHITELIST.indexOf(library) != -1) { // Go straight into node_modules // Avoid `require.resolve()`, since 'mustache' and 'mustache/index.js' diff --git a/src/node/utils/Settings.js b/src/node/utils/Settings.js index 7e0e6c5a1..b7d1f0bc3 100644 --- a/src/node/utils/Settings.js +++ b/src/node/utils/Settings.js @@ -28,6 +28,7 @@ var jsonminify = require("jsonminify"); var log4js = require("log4js"); var randomString = require("./randomstring"); var suppressDisableMsg = " -- To suppress these warning messages change suppressErrorsInPadText to true in your settings.json\n"; +var _ = require("underscore"); /* Root path of the installation */ exports.root = path.normalize(path.join(npm.dir, "..")); @@ -84,6 +85,23 @@ exports.dbSettings = { "filename" : path.join(exports.root, "dirty.db") }; */ exports.defaultPadText = "Welcome to Etherpad!\n\nThis pad text is synchronized as you type, so that everyone viewing this page sees the same text. This allows you to collaborate seamlessly on documents!\n\nEtherpad on Github: http:\/\/j.mp/ep-lite\n"; +/** + * The default Pad Settings for a user (Can be overridden by changing the setting + */ +exports.padOptions = { + "noColors": false, + "showControls": true, + "showChat": true, + "showLineNumbers": true, + "useMonospaceFont": false, + "userName": false, + "userColor": false, + "rtl": false, + "alwaysShowChat": false, + "chatAndUsers": false, + "lang": "en-gb" +} + /** * The toolbar buttons and order. */ @@ -255,7 +273,11 @@ exports.reloadSettings = function reloadSettings() { //or it's a settings hash, specific to a plugin if(exports[i] !== undefined || i.indexOf('ep_')==0) { - exports[i] = settings[i]; + if (_.isObject(settings[i]) && !_.isArray(settings[i])) { + exports[i] = _.defaults(settings[i], exports[i]); + } else { + exports[i] = settings[i]; + } } //this setting is unkown, output a warning and throw it away else @@ -286,13 +308,15 @@ exports.reloadSettings = function reloadSettings() { } } - if(!exports.sessionKey){ // If the secretKey isn't set we also create yet another unique value here - exports.sessionKey = randomString(32); - var sessionWarning = "You need to set a sessionKey value in settings.json, this will allow your users to reconnect to your Etherpad Instance if your instance restarts"; - if(!exports.suppressErrorsInPadText){ - exports.defaultPadText = exports.defaultPadText + "\nWarning: " + sessionWarning + suppressDisableMsg; + if (!exports.sessionKey) { + try { + exports.sessionKey = fs.readFileSync("./SESSIONKEY.txt","utf8"); + } catch(e) { + exports.sessionKey = randomString(32); + fs.writeFileSync("./SESSIONKEY.txt",exports.sessionKey,"utf8"); } - console.warn(sessionWarning); + } else { + console.warn("Declaring the sessionKey in the settings.json is deprecated. This value is auto-generated now. Please remove the setting from the file."); } if(exports.dbType === "dirty"){ diff --git a/src/package.json b/src/package.json index 3d3a25145..fdeb8edf3 100644 --- a/src/package.json +++ b/src/package.json @@ -56,5 +56,5 @@ "repository" : { "type" : "git", "url" : "http://github.com/ether/etherpad-lite.git" }, - "version" : "1.5.4" + "version" : "1.5.6" } diff --git a/src/static/js/ace2_inner.js b/src/static/js/ace2_inner.js index 70a867488..f8c2565ea 100644 --- a/src/static/js/ace2_inner.js +++ b/src/static/js/ace2_inner.js @@ -1920,7 +1920,11 @@ function Ace2Inner(){ if (charsLeft === 0) { var index = 0; - browser.msie = false; // Temp fix to resolve enter and backspace issues.. + + if (browser.msie && parseInt(browser.version) >= 11) { + browser.msie = false; // Temp fix to resolve enter and backspace issues.. + // Note that this makes MSIE behave like modern browsers.. + } if (browser.msie && line == (rep.lines.length() - 1) && lineNode.childNodes.length === 0) { // best to stay at end of last empty div in IE diff --git a/src/static/js/html10n.js b/src/static/js/html10n.js index 19cf9de18..44abd7a0b 100644 --- a/src/static/js/html10n.js +++ b/src/static/js/html10n.js @@ -681,9 +681,9 @@ window.html10n = (function(window, document, undefined) { // Expand two-part locale specs var i=0 langs.forEach(function(lang) { - if(!lang) return - langs[i++] = lang - if(~lang.indexOf('-')) langs[i++] = lang.substr(0, lang.indexOf('-')) + if(!lang) return; + langs[i++] = lang; + if(~lang.indexOf('-')) langs[i++] = lang.substr(0, lang.indexOf('-')); }) this.build(langs, function(er, translations) { diff --git a/src/static/js/pad.js b/src/static/js/pad.js index 4072ca3c2..ee3bab528 100644 --- a/src/static/js/pad.js +++ b/src/static/js/pad.js @@ -68,43 +68,6 @@ define([ time: 6000 // hang on the screen for... }); - function createCookie(name, value, days, path){ /* Warning Internet Explorer doesn't use this it uses the one from pad_utils.js */ - if (days) - { - var date = new Date(); - date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000)); - var expires = "; expires=" + date.toGMTString(); - } - else{ - var expires = ""; - } - - if(!path){ // If the path isn't set then just whack the cookie on the root path - path = "/"; - } - - //Check if the browser is IE and if so make sure the full path is set in the cookie - if((navigator.appName == 'Microsoft Internet Explorer') || ((navigator.appName == 'Netscape') && (new RegExp("Trident/.*rv:([0-9]{1,}[\.0-9]{0,})").exec(navigator.userAgent) != null))){ - document.cookie = name + "=" + value + expires + "; path="+document.location; - } - else{ - document.cookie = name + "=" + value + expires + "; path=" + path; - } - } - - function readCookie(name) - { - var nameEQ = name + "="; - var ca = document.cookie.split(';'); - for (var i = 0; i < ca.length; i++) - { - var c = ca[i]; - while (c.charAt(0) == ' ') c = c.substring(1, c.length); - if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length); - } - return null; - } - // This array represents all GET-parameters which can be used to change a setting. // name: the parameter-name, eg `?noColors=true` => `noColors` // checkVal: the callback is only executed when @@ -412,6 +375,7 @@ define([ }, getIsDebugEnabled: function() { +<<<<<<< HEAD return clientVars.debugEnabled; }, getPrivilege: function(name) @@ -445,6 +409,11 @@ define([ var newHref = "/p/" + padId; if (options != null) newHref = newHref + '?' + options; +======= + // start the custom js + if (typeof customStart == "function") customStart(); + handshake(); +>>>>>>> d31523aa08d123f421248e249e2194f7689f0b06 if(window.history && window.history.pushState) { @@ -453,7 +422,33 @@ define([ receivedClientVars = false; sendClientReady(false, 'SWITCH_TO_PAD'); } +<<<<<<< HEAD else // fallback +======= + }); + }, + _afterHandshake: function() + { + pad.clientTimeOffset = new Date().getTime() - clientVars.serverTimestamp; + + //initialize the chat + chat.init(this); + getParams(); + + padcookie.init(); // initialize the cookies + pad.initTime = +(new Date()); + pad.padOptions = clientVars.initialOptions; + + if ((!browser.msie) && (!(browser.firefox && browser.version.indexOf("1.8.") == 0))) + { + document.domain = document.domain; // for comet + } + + // for IE + if (browser.msie) + { + try +>>>>>>> d31523aa08d123f421248e249e2194f7689f0b06 { window.location.href = newHref; } diff --git a/src/static/js/pad_editor.js b/src/static/js/pad_editor.js index 088455d94..c8d838d36 100644 --- a/src/static/js/pad_editor.js +++ b/src/static/js/pad_editor.js @@ -144,8 +144,6 @@ define([ var v; v = getOption('rtlIsTrue', ('rtl' == html10n.getDirection())); - // Override from parameters if true - if(settings.rtlIsTrue === true) v = true; self.ace.setProperty("rtlIsTrue", v); padutils.setCheckbox($("#options-rtlcheck"), v); diff --git a/tests/frontend/travis/remote_runner.js b/tests/frontend/travis/remote_runner.js index b94d8c3ed..f7b21ed52 100644 --- a/tests/frontend/travis/remote_runner.js +++ b/tests/frontend/travis/remote_runner.js @@ -82,16 +82,18 @@ sauceTestWorker.push({ , 'version' : '' }); +/* // IE 8 sauceTestWorker.push({ 'platform' : 'Windows 2003' , 'browserName' : 'iexplore' , 'version' : '8' }); +*/ // IE 9 sauceTestWorker.push({ - 'platform' : 'Windows 2008' + 'platform' : 'Windows XP' , 'browserName' : 'iexplore' , 'version' : '9' });