Merge new release into master branch!

This commit is contained in:
Stefan 2015-04-13 17:27:37 +02:00
commit 24b0712d77
40 changed files with 224 additions and 136 deletions

1
.gitignore vendored
View File

@ -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

View File

@ -1,3 +1,16 @@
# 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

View File

@ -22,7 +22,7 @@ Also, check out the **[FAQ](https://github.com/ether/etherpad-lite/wiki/FAQ)**,
# Installation
Etherpad works with node v0.8, v0.10 and v0.11, only. (We don't support v0.6)
Etherpad works with node v0.10+ and io.js.
## Windows

View File

@ -1,6 +1,6 @@
#!/bin/sh
NODE_VERSION="0.8.4"
NODE_VERSION="0.10.38"
#Move to the folder where ep-lite is installed
cd `dirname $0`

View File

@ -50,9 +50,9 @@ NODE_V_MINOR=$(echo $NODE_VERSION | cut -d "." -f 1-2)
if hash iojs 2>/dev/null; then
IOJS_VERSION=$(iojs --version)
fi
if [ ! $NODE_V_MINOR = "v0.8" ] && [ ! $NODE_V_MINOR = "v0.10" ] && [ ! $NODE_V_MINOR = "v0.11" ] && [ ! $NODE_V_MINOR = "v0.12" ]; then
if [ ! $NODE_V_MINOR = "v0.10" ] && [ ! $NODE_V_MINOR = "v0.11" ] && [ ! $NODE_V_MINOR = "v0.12" ]; then
if [ ! $IOJS_VERSION ]; then
echo "You're running a wrong version of node, or io.js is not installed. You're using $NODE_VERSION, we need v0.8.x, v0.10.x, v0.11.x or v0.12.x" >&2
echo "You're running a wrong version of node, or io.js is not installed. You're using $NODE_VERSION, we need v0.10.x, v0.11.x or v0.12.x" >&2
exit 1
fi
fi

View File

@ -8,7 +8,7 @@ cmd /C node -e "" || ( echo "Please install node.js ( http://nodejs.org )" && ex
echo _
echo Checking node version...
set check_version="if(['8','10'].indexOf(process.version.split('.')[1].toString()) === -1) { console.log('You are running a wrong version of Node. Etherpad requires v0.8.x or v0.10.x'); process.exit(1) }"
set check_version="if(['10','11','12'].indexOf(process.version.split('.')[1]) === -1 && process.version.split('.')[0] !== '1') { console.log('You are running a wrong version of Node. Etherpad requires v0.10+'); process.exit(1) }"
cmd /C node -e %check_version% || exit /B 1
echo _

View File

@ -61,7 +61,7 @@ Portal submits content into new blog post
## Usage
### API version
The latest version is `1.2.11`
The latest version is `1.2.12`
The current version can be queried via /api.
@ -232,7 +232,7 @@ creates a new session. validUntil is an unix timestamp in seconds
deletes a session
*Example returns:*
* `{code: 1, message:"ok", data: null}`
* `{code: 0, message:"ok", data: null}`
* `{code: 1, message:"sessionID does not exist", data: null}`
#### getSessionInfo(sessionID)
@ -388,10 +388,12 @@ Group pads are normal pads, but with the name schema GROUPID$PADNAME. A security
* API >= 1
creates a new (non-group) pad. Note that if you need to create a group Pad, you should call **createGroupPad**.
You get an error message if you use one of the following characters in the padID: "/", "?", "&" or "#".
*Example returns:*
* `{code: 0, message:"ok", data: null}`
* `{code: 1, message:"pad does already exist", data: null}`
* `{code: 1, message:"padID does already exist", data: null}`
* `{code: 1, message:"malformed padID: Remove special characters", data: null}`
#### getRevisionsCount(padID)
* API >= 1

View File

@ -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,

View File

@ -687,12 +687,21 @@ Example returns:
exports.createPad = function(padID, text, callback)
{
//ensure there is no $ in the padID
if(padID && padID.indexOf("$") != -1)
if(padID)
{
callback(new customError("createPad can't create group pads","apierror"));
return;
if(padID.indexOf("$") != -1)
{
callback(new customError("createPad can't create group pads","apierror"));
return;
}
//check for url special characters
else if(padID.match(/(\/|\?|&|#)/))
{
callback(new customError("malformed padID: Remove special characters","apierror"));
return;
}
}
//create pad
getPadSafe(padID, false, text, function(err)
{

View File

@ -4,7 +4,7 @@
* This is not used for authors that are created via the API at current
*/
var Store = require('ep_etherpad-lite/node_modules/connect/lib/middleware/session/store'),
var Store = require('ep_etherpad-lite/node_modules/express-session').Store,
db = require('ep_etherpad-lite/node/db/DB').db,
log4js = require('ep_etherpad-lite/node_modules/log4js'),
messageLogger = log4js.getLogger("SessionStore");

View File

@ -26,7 +26,7 @@ var hooks = require("ep_etherpad-lite/static/js/pluginfw/hooks.js");
var resolve = require("resolve");
exports.info = {
buf_stack: [],
__output_stack: [],
block_stack: [],
file_stack: [],
args: []
@ -41,27 +41,27 @@ function createBlockId(name) {
}
exports._init = function (b, recursive) {
exports.info.buf_stack.push(exports.info.buf);
exports.info.buf = b;
exports.info.__output_stack.push(exports.info.__output);
exports.info.__output = b;
}
exports._exit = function (b, recursive) {
getCurrentFile().inherit.forEach(function (item) {
exports._require(item.name, item.args);
});
exports.info.buf = exports.info.buf_stack.pop();
exports.info.__output = exports.info.__output_stack.pop();
}
exports.begin_capture = function() {
exports.info.buf_stack.push(exports.info.buf.concat());
exports.info.buf.splice(0, exports.info.buf.length);
exports.info.__output_stack.push(exports.info.__output.concat());
exports.info.__output.splice(0, exports.info.__output.length);
}
exports.end_capture = function () {
var res = exports.info.buf.join("");
exports.info.buf.splice.apply(
exports.info.buf,
[0, exports.info.buf.length].concat(exports.info.buf_stack.pop()));
var res = exports.info.__output.join("");
exports.info.__output.splice.apply(
exports.info.__output,
[0, exports.info.__output.length].concat(exports.info.__output_stack.pop()));
return res;
}
@ -80,7 +80,7 @@ exports.end_block = function () {
var renderContext = exports.info.args[exports.info.args.length-1];
var args = {content: exports.end_define_block(), renderContext: renderContext};
hooks.callAll("eejsBlock_" + name, args);
exports.info.buf.push(args.content);
exports.info.__output.push(args.content);
}
exports.begin_block = exports.begin_define_block;
@ -114,7 +114,7 @@ exports.require = function (name, args, mod) {
args.e = exports;
args.require = require;
var template = '<% e._init(buf); %>' + fs.readFileSync(ejspath).toString() + '<% e._exit(); %>';
var template = '<% e._init(__output); %>' + fs.readFileSync(ejspath).toString() + '<% e._exit(); %>';
exports.info.args.push(args);
exports.info.file_stack.push({path: ejspath, inherit: []});
@ -127,5 +127,5 @@ exports.require = function (name, args, mod) {
}
exports._require = function (name, args) {
exports.info.buf.push(exports.require(name, args));
exports.info.__output.push(exports.require(name, args));
}

View File

@ -103,7 +103,7 @@ exports.doExport = function(req, res, padId, type)
//send the file
function(callback)
{
res.sendfile(destFile, null, callback);
res.sendFile(destFile, null, callback);
},
//clean up temporary files
function(callback)
@ -184,7 +184,7 @@ exports.doExport = function(req, res, padId, type)
//send the file
function(callback)
{
res.sendfile(destFile, null, callback);
res.sendFile(destFile, null, callback);
},
//clean up temporary files
function(callback)

View File

@ -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<len; i++) {
if (buf[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<len; i++) {
if (buf[i] > 240) {
isAscii=false;
break;
}
if (isAscii) {
callback();
} else {
callback("uploadFailed");
}
});
}else{
callback();
}
}
if (isAscii) {
callback();
} else {
callback("uploadFailed");
}
});
} else {
callback();
}
@ -303,7 +297,7 @@ exports.doImport = function(req, res, padId)
var impexp = window.parent.padimpexp.handleFrameCall('" + directDatabaseAccess +"', '" + status + "'); \
}) \
</script>"
, 200);
);
});
}

View File

@ -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

View File

@ -69,10 +69,8 @@ exports.restartServer = function () {
if(settings.trustProxy){
app.enable('trust proxy');
}
app.configure(function() {
hooks.callAll("expressConfigure", {"app": app});
});
hooks.callAll("expressConfigure", {"app": app});
hooks.callAll("expressCreateServer", {"app": app, "server": server});
server.listen(settings.port, settings.ip);

View File

@ -39,7 +39,7 @@ exports.expressCreateServer = function (hook_name, args, cb) {
// if an error occurs Connect will pass it down
// through these "error-handling" middleware
// allowing you to respond however you like
res.send(500, { error: 'Sorry, something bad happened!' });
res.status(500).send({ error: 'Sorry, something bad happened!' });
console.error(err.stack? err.stack : err.toString());
stats.meter('http500').mark()
})
@ -50,4 +50,4 @@ exports.expressCreateServer = function (hook_name, args, cb) {
//https://github.com/joyent/node/issues/1553
process.on('SIGINT', exports.gracefulShutdown);
}
}
}

View File

@ -55,7 +55,7 @@ exports.expressCreateServer = function (hook_name, args, cb) {
ERR(err);
if(err == "notfound")
res.send(404, '404 - Not Found');
res.status(404).send('404 - Not Found');
else
res.send(html);
});

View File

@ -7,7 +7,7 @@ exports.expressCreateServer = function (hook_name, args, cb) {
//ensure the padname is valid and the url doesn't end with a /
if(!padManager.isValidPadId(padId) || /\/$/.test(req.url))
{
res.send(404, 'Such a padname is forbidden');
res.status(404).send('Such a padname is forbidden');
}
else
{
@ -19,7 +19,7 @@ exports.expressCreateServer = function (hook_name, args, cb) {
var query = url.parse(req.url).query;
if ( query ) real_url += '?' + query;
res.header('Location', real_url);
res.send(302, 'You should be redirected to <a href="' + real_url + '">' + real_url + '</a>');
res.status(302).send('You should be redirected to <a href="' + real_url + '">' + real_url + '</a>');
}
//the pad id was fine, so just render it
else

View File

@ -6,7 +6,8 @@ var webaccess = require("ep_etherpad-lite/node/hooks/express/webaccess");
var padMessageHandler = require("../../handler/PadMessageHandler");
var connect = require('connect');
var cookieParser = require('cookie-parser');
var sessionModule = require('express-session');
exports.expressCreateServer = function (hook_name, args, cb) {
//init socket.io and redirect all requests to the MessageHandler
@ -20,6 +21,7 @@ exports.expressCreateServer = function (hook_name, args, cb) {
/* Require an express session cookie to be present, and load the
* session. See http://www.danielbaulig.de/socket-ioexpress for more
* info */
var cookieParserFn = cookieParser(webaccess.secret, {});
io.use(function(socket, accept) {
var data = socket.request;
@ -29,8 +31,7 @@ exports.expressCreateServer = function (hook_name, args, cb) {
}else{
if (!data.headers.cookie) return accept('No session cookie transmitted.', false);
}
// Use connect's cookie parser, because it knows how to parse signed cookies
connect.cookieParser(webaccess.secret)(data, {}, function(err){
cookieParserFn(data, {}, function(err){
if(err) {
console.error(err);
accept("Couldn't parse request cookies. ", false);
@ -40,7 +41,7 @@ exports.expressCreateServer = function (hook_name, args, cb) {
data.sessionID = data.signedCookies.express_sid;
args.app.sessionStore.get(data.sessionID, function (err, session) {
if (err || !session) return accept('Bad session / session has expired', false);
data.session = new connect.middleware.session.Session(data, session);
data.session = new sessionModule.Session(data, session);
accept(null, true);
});
});

View File

@ -19,13 +19,13 @@ exports.expressCreateServer = function (hook_name, args, cb) {
args.app.get('/robots.txt', function(req, res)
{
var filePath = path.normalize(__dirname + "/../../../static/custom/robots.txt");
res.sendfile(filePath, function(err)
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");
res.sendfile(filePath);
res.sendFile(filePath);
}
});
});
@ -60,13 +60,13 @@ exports.expressCreateServer = function (hook_name, args, cb) {
args.app.get( /\/favicon.ico$/, function(req, res)
{
var filePath = path.normalize(__dirname + "/../../../static/custom/favicon.ico");
res.sendfile(filePath, function(err)
res.sendFile(filePath, function(err)
{
//there is no custom favicon, send the default favicon
if(err)
{
filePath = path.normalize(__dirname + "/../../../static/favicon.ico");
res.sendfile(filePath);
res.sendFile(filePath);
}
});
});

View File

@ -9,7 +9,7 @@ exports.expressCreateServer = function (hook_name, args, cb) {
// Cache both minified and static.
var assetCache = new CachingMiddleware;
args.app.all('/(javascripts|static)/*', assetCache.handle);
args.app.all(/\/javascripts\/(.*)/, assetCache.handle);
// Minify will serve static files compressed (minify enabled). It also has
// file-specific hacks for ace/require-kernel/etc.
@ -30,7 +30,8 @@ exports.expressCreateServer = function (hook_name, args, cb) {
Yajsml.associators.associationsForSimpleMapping(minify.tar);
var associator = new StaticAssociator(associations);
jsServer.setAssociator(associator);
args.app.use(jsServer);
args.app.use(jsServer.handle.bind(jsServer));
// serve plugin definitions
// not very static, but served here so that client can do require("pluginfw/static/js/plugin-definitions.js");

View File

@ -57,7 +57,7 @@ exports.expressCreateServer = function (hook_name, args, cb) {
args.app.get('/tests/frontend/*', function (req, res) {
var filePath = url2FilePath(req.url);
res.sendfile(filePath);
res.sendFile(filePath);
});
args.app.get('/tests/frontend', function (req, res) {

View File

@ -4,7 +4,8 @@ var httpLogger = log4js.getLogger("http");
var settings = require('../../utils/Settings');
var hooks = require('ep_etherpad-lite/static/js/pluginfw/hooks');
var ueberStore = require('../../db/SessionStore');
var stats = require('ep_etherpad-lite/node/stats')
var stats = require('ep_etherpad-lite/node/stats');
var sessionModule = require('express-session');
//checks for basic http auth
exports.basicAuth = function (req, res, next) {
@ -56,10 +57,10 @@ exports.basicAuth = function (req, res, next) {
res.header('WWW-Authenticate', 'Basic realm="Protected Area"');
if (req.headers.authorization) {
setTimeout(function () {
res.send(401, 'Authentication required');
res.status(401).send('Authentication required');
}, 1000);
} else {
res.send(401, 'Authentication required');
res.status(401).send('Authentication required');
}
}));
}
@ -117,9 +118,8 @@ exports.expressConfigure = function (hook_name, args, cb) {
exports.secret = settings.sessionKey; // Isn't this being reset each time the server spawns?
}
args.app.use(express.cookieParser(exports.secret));
args.app.sessionStore = exports.sessionStore;
args.app.use(express.session({secret: exports.secret, store: args.app.sessionStore, key: 'express_sid' }));
args.app.use(sessionModule({secret: exports.secret, store: args.app.sessionStore, resave: true, saveUninitialized: true, name: 'express_sid' }));
args.app.use(exports.basicAuth);
}

View File

@ -91,7 +91,7 @@ exports.expressCreateServer = function(n, args) {
res.setHeader('Content-Type', 'application/json; charset=utf-8');
res.send('{"'+locale+'":'+JSON.stringify(locales[locale])+'}');
} else {
res.send(404, 'Language not available');
res.status(404).send('Language not available');
}
})

View File

@ -15,7 +15,7 @@ module.exports = function (req, res, callback) {
callback();
//no access
} else {
res.send(403, "403 - Can't touch this");
res.status(403).send("403 - Can't touch this");
}
});
}

View File

@ -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);
});

View File

@ -165,7 +165,6 @@ 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?)
} else if (LIBRARY_WHITELIST.indexOf(library) != -1) {
// Go straight into node_modules
// Avoid `require.resolve()`, since 'mustache' and 'mustache/index.js'

View File

@ -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"){

View File

@ -14,45 +14,46 @@
"dependencies" : {
"etherpad-yajsml" : "0.0.2",
"request" : "2.55.0",
"etherpad-require-kernel" : "1.0.8",
"etherpad-require-kernel" : "1.0.9",
"resolve" : "1.1.6",
"socket.io" : "1.3.5",
"ueberDB" : "0.2.15",
"express" : "3.8.1",
"express" : "4.12.3",
"express-session" : "1.11.1",
"cookie-parser" : "1.3.4",
"async" : "0.9.0",
"connect" : "2.7.11",
"clean-css" : "3.1.9",
"uglify-js" : "2.4.19",
"formidable" : "1.0.17",
"log4js" : "0.6.22",
"cheerio" : "0.19.0",
"async-stacktrace" : "0.0.2",
"npm" : "2.7.5",
"ejs" : "1.0.0",
"npm" : "2.7.6",
"ejs" : "2.3.1",
"graceful-fs" : "3.0.6",
"slide" : "1.1.6",
"semver" : "4.3.3",
"security" : "1.0.0",
"tinycon" : "0.0.1",
"underscore" : "1.5.1",
"underscore" : "1.8.3",
"unorm" : "1.3.3",
"languages4translatewiki" : "0.1.3",
"swagger-node-express" : "2.1.3",
"channels" : "0.0.4",
"jsonminify" : "0.2.3",
"measured" : "1.0.0",
"mocha" : "2.2.1",
"mocha" : "2.2.4",
"supertest" : "0.15.0"
},
"bin": { "etherpad-lite": "./node/server.js" },
"devDependencies": {
"wd" : "0.3.11"
},
"engines" : { "node" : ">=0.6.3",
"engines" : { "node" : ">=0.10.0",
"npm" : ">=1.0"
},
"repository" : { "type" : "git",
"url" : "http://github.com/ether/etherpad-lite.git"
},
"version" : "1.5.4"
"version" : "1.5.5"
}

View File

@ -210,8 +210,9 @@ ol {
list-style-type: decimal;
}
/* Fixes #2223 and #1836 */
ol > li {
display:inline;
display:block;
}
/* Set the indentation */

View File

@ -1923,7 +1923,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
@ -4955,7 +4959,10 @@ function Ace2Inner(){
// Don't paste on middle click of links
$(root).on("paste", function(e){
if(e.target.a){
// TODO: this breaks pasting strings into URLS when using
// Control C and Control V -- the Event is never available
// here.. :(
if(e.target.a || e.target.localName === "a"){
e.preventDefault();
}
})

View File

@ -166,6 +166,7 @@ function loadBroadcastSliderJS(fireWhenAllScriptsAreLoaded)
padmodals.showModal("disconnected");
}
// Throttle seems like overkill here... Not sure why we do it!
var fixPadHeight = _.throttle(function(){
var height = $('#timeslider-top').height();
$('#editorcontainerbox').css({marginTop: height});

View File

@ -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) {

View File

@ -126,6 +126,18 @@ var getParameters = [
function getParams()
{
// Tries server enforced options first..
for(var i = 0; i < getParameters.length; i++)
{
var setting = getParameters[i];
var value = clientVars.padOptions[setting.name];
if(value.toString() === setting.checkVal)
{
setting.callback(value);
}
}
// Then URL applied stuff
var params = getUrlVars()
for(var i = 0; i < getParameters.length; i++)
@ -475,7 +487,6 @@ var pad = {
{
// start the custom js
if (typeof customStart == "function") customStart();
getParams();
handshake();
// To use etherpad you have to allow cookies.
@ -495,6 +506,8 @@ var pad = {
//initialize the chat
chat.init(this);
getParams();
padcookie.init(); // initialize the cookies
pad.initTime = +(new Date());
pad.padOptions = clientVars.initialOptions;

View File

@ -136,8 +136,6 @@ var padeditor = (function()
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);

View File

@ -2,7 +2,8 @@ var assert = require('assert')
supertest = require(__dirname+'/../../../../src/node_modules/supertest'),
fs = require('fs'),
api = supertest('http://localhost:9001');
path = require('path');
path = require('path'),
async = require(__dirname+'/../../../../src/node_modules/async');
var filePath = path.join(__dirname, '../../../../APIKEY.txt');
@ -80,6 +81,7 @@ describe('Permission', function(){
-> setHTML(padID) -- Should fail on invalid HTML
-> setHTML(padID) *3 -- Should fail on invalid HTML
-> getHTML(padID) -- Should return HTML close to posted HTML
-> createPad -- Tries to create pads with bad url characters
*/
@ -494,6 +496,23 @@ describe('getHTML', function(){
});
})
describe('createPad', function(){
it('errors if pad can be created', function(done) {
var badUrlChars = ["/", "%23", "%3F", "%26"];
async.map(
badUrlChars,
function (badUrlChar, cb) {
api.get(endPoint('createPad')+"&padID="+badUrlChar)
.expect(function(res){
if(res.body.code !== 1) throw new Error("Pad with bad characters was created");
})
.expect('Content-Type', /json/)
.end(cb);
},
done);
});
})
/*
-> movePadForce Test

View File

@ -24,7 +24,8 @@ describe("font select", function(){
//check if font changed to monospace
var fontFamily = inner$("body").css("font-family").toLowerCase();
expect(fontFamily).to.be("courier new");
var containsStr = fontFamily.indexOf("courier new");
expect(containsStr).to.not.be(-1);
done();
});

View File

@ -52,7 +52,7 @@ describe("import functionality", function(){
return exportresults
}
it("import a pad with newlines from txt", function(done){
xit("import a pad with newlines from txt", function(done){
var importurl = helper.padChrome$.window.location.href+'/import'
var textWithNewLines = 'imported text\nnewline'
importrequest(textWithNewLines,importurl,"txt")
@ -64,7 +64,7 @@ describe("import functionality", function(){
expect(results[1][1]).to.be("imported text\nnewline\n\n")
done()
})
it("import a pad with newlines from html", function(done){
xit("import a pad with newlines from html", function(done){
var importurl = helper.padChrome$.window.location.href+'/import'
var htmlWithNewLines = '<html><body>htmltext<br/>newline</body></html>'
importrequest(htmlWithNewLines,importurl,"html")
@ -76,7 +76,7 @@ describe("import functionality", function(){
expect(results[1][1]).to.be("htmltext\nnewline\n\n")
done()
})
it("import a pad with attributes from html", function(done){
xit("import a pad with attributes from html", function(done){
var importurl = helper.padChrome$.window.location.href+'/import'
var htmlWithNewLines = '<html><body>htmltext<br/><span class="b s i u"><b><i><s><u>newline</u></s></i></b></body></html>'
importrequest(htmlWithNewLines,importurl,"html")
@ -88,7 +88,7 @@ describe("import functionality", function(){
expect(results[1][1]).to.be('htmltext\nnewline\n\n')
done()
})
it("import a pad with bullets from html", function(done){
xit("import a pad with bullets from html", function(done){
var importurl = helper.padChrome$.window.location.href+'/import'
var htmlWithBullets = '<html><body><ul class="list-bullet1"><li>bullet line 1</li><li>bullet line 2</li><ul class="list-bullet2"><li>bullet2 line 1</li><li>bullet2 line 2</li></ul></ul></body></html>'
importrequest(htmlWithBullets,importurl,"html")
@ -105,7 +105,7 @@ describe("import functionality", function(){
expect(results[1][1]).to.be('\t* bullet line 1\n\t* bullet line 2\n\t\t* bullet2 line 1\n\t\t* bullet2 line 2\n\n')
done()
})
it("import a pad with bullets and newlines from html", function(done){
xit("import a pad with bullets and newlines from html", function(done){
var importurl = helper.padChrome$.window.location.href+'/import'
var htmlWithBullets = '<html><body><ul class="list-bullet1"><li>bullet line 1</li></ul><br/><ul class="list-bullet1"><li>bullet line 2</li><ul class="list-bullet2"><li>bullet2 line 1</li></ul></ul><br/><ul class="list-bullet1"><ul class="list-bullet2"><li>bullet2 line 2</li></ul></ul></body></html>'
importrequest(htmlWithBullets,importurl,"html")
@ -124,7 +124,7 @@ describe("import functionality", function(){
expect(results[1][1]).to.be('\t* bullet line 1\n\n\t* bullet line 2\n\t\t* bullet2 line 1\n\n\t\t* bullet2 line 2\n\n')
done()
})
it("import a pad with bullets and newlines and attributes from html", function(done){
xit("import a pad with bullets and newlines and attributes from html", function(done){
var importurl = helper.padChrome$.window.location.href+'/import'
var htmlWithBullets = '<html><body><ul class="list-bullet1"><li>bullet line 1</li></ul><br/><ul class="list-bullet1"><li>bullet line 2</li><ul class="list-bullet2"><li>bullet2 line 1</li></ul></ul><br/><ul class="list-bullet1"><ul class="list-bullet2"><ul class="list-bullet3"><ul class="list-bullet4"><li><span class="b s i u"><b><i><s><u>bullet4 line 2 bisu</u></s></i></b></span></li><li><span class="b s "><b><s>bullet4 line 2 bs</s></b></span></li><li><span class="u"><u>bullet4 line 2 u</u></span><span class="u i s"><i><s><u>uis</u></s></i></span></li></ul></ul></ul></ul></body></html>'
importrequest(htmlWithBullets,importurl,"html")
@ -143,7 +143,7 @@ describe("import functionality", function(){
expect(results[1][1]).to.be('\t* bullet line 1\n\n\t* bullet line 2\n\t\t* bullet2 line 1\n\n\t\t\t\t* bullet4 line 2 bisu\n\t\t\t\t* bullet4 line 2 bs\n\t\t\t\t* bullet4 line 2 uuis\n\n')
done()
})
it("import a pad with nested bullets from html", function(done){
xit("import a pad with nested bullets from html", function(done){
var importurl = helper.padChrome$.window.location.href+'/import'
var htmlWithBullets = '<html><body><ul class="list-bullet1"><li>bullet line 1</li></ul><ul class="list-bullet1"><li>bullet line 2</li><ul class="list-bullet2"><li>bullet2 line 1</li></ul></ul><ul class="list-bullet1"><ul class="list-bullet2"><ul class="list-bullet3"><ul class="list-bullet4"><li>bullet4 line 2</li><li>bullet4 line 2</li><li>bullet4 line 2</li></ul><li>bullet3 line 1</li></ul></ul><li>bullet2 line 1</li></ul></body></html>'
importrequest(htmlWithBullets,importurl,"html")
@ -165,7 +165,7 @@ describe("import functionality", function(){
expect(results[1][1]).to.be('\t* bullet line 1\n\t* bullet line 2\n\t\t* bullet2 line 1\n\t\t\t\t* bullet4 line 2\n\t\t\t\t* bullet4 line 2\n\t\t\t\t* bullet4 line 2\n\t\t\t* bullet3 line 1\n\t* bullet2 line 1\n\n')
done()
})
it("import a pad with 8 levels of bullets and newlines and attributes from html", function(done){
xit("import a pad with 8 levels of bullets and newlines and attributes from html", function(done){
var importurl = helper.padChrome$.window.location.href+'/import'
var htmlWithBullets = '<html><body><ul class="list-bullet1"><li>bullet line 1</li></ul><br/><ul class="list-bullet1"><li>bullet line 2</li><ul class="list-bullet2"><li>bullet2 line 1</li></ul></ul><br/><ul class="list-bullet1"><ul class="list-bullet2"><ul class="list-bullet3"><ul class="list-bullet4"><li><span class="b s i u"><b><i><s><u>bullet4 line 2 bisu</u></s></i></b></span></li><li><span class="b s "><b><s>bullet4 line 2 bs</s></b></span></li><li><span class="u"><u>bullet4 line 2 u</u></span><span class="u i s"><i><s><u>uis</u></s></i></span></li><ul class="list-bullet5"><ul class="list-bullet6"><ul class="list-bullet7"><ul class="list-bullet8"><li><span class="">foo</span></li><li><span class="b s"><b><s>foobar bs</b></s></span></li></ul></ul></ul></ul><ul class="list-bullet5"><li>foobar</li></ul></ul></ul></ul></body></html>'
importrequest(htmlWithBullets,importurl,"html")

View File

@ -49,7 +49,7 @@ describe("import indents functionality", function(){
return exportresults
}
it("import a pad with indents from html", function(done){
xit("import a pad with indents from html", function(done){
var importurl = helper.padChrome$.window.location.href+'/import'
var htmlWithIndents = '<html><body><ul class="list-indent1"><li>indent line 1</li><li>indent line 2</li><ul class="list-indent2"><li>indent2 line 1</li><li>indent2 line 2</li></ul></ul></body></html>'
importrequest(htmlWithIndents,importurl,"html")
@ -67,7 +67,7 @@ describe("import indents functionality", function(){
done()
})
it("import a pad with indented lists and newlines from html", function(done){
xit("import a pad with indented lists and newlines from html", function(done){
var importurl = helper.padChrome$.window.location.href+'/import'
var htmlWithIndents = '<html><body><ul class="list-indent1"><li>indent line 1</li></ul><br/><ul class="list-indent1"><li>indent 1 line 2</li><ul class="list-indent2"><li>indent 2 times line 1</li></ul></ul><br/><ul class="list-indent1"><ul class="list-indent2"><li>indent 2 times line 2</li></ul></ul></body></html>'
importrequest(htmlWithIndents,importurl,"html")
@ -86,7 +86,7 @@ describe("import indents functionality", function(){
expect(results[1][1]).to.be('\tindent line 1\n\n\tindent 1 line 2\n\t\tindent 2 times line 1\n\n\t\tindent 2 times line 2\n\n')
done()
})
it("import a pad with 8 levels of indents and newlines and attributes from html", function(done){
xit("import a pad with 8 levels of indents and newlines and attributes from html", function(done){
var importurl = helper.padChrome$.window.location.href+'/import'
var htmlWithIndents = '<html><body><ul class="list-indent1"><li>indent line 1</li></ul><br/><ul class="list-indent1"><li>indent line 2</li><ul class="list-indent2"><li>indent2 line 1</li></ul></ul><br/><ul class="list-indent1"><ul class="list-indent2"><ul class="list-indent3"><ul class="list-indent4"><li><span class="b s i u"><b><i><s><u>indent4 line 2 bisu</u></s></i></b></span></li><li><span class="b s "><b><s>indent4 line 2 bs</s></b></span></li><li><span class="u"><u>indent4 line 2 u</u></span><span class="u i s"><i><s><u>uis</u></s></i></span></li><ul class="list-indent5"><ul class="list-indent6"><ul class="list-indent7"><ul class="list-indent8"><li><span class="">foo</span></li><li><span class="b s"><b><s>foobar bs</b></s></span></li></ul></ul></ul></ul><ul class="list-indent5"><li>foobar</li></ul></ul></ul></ul></body></html>'
importrequest(htmlWithIndents,importurl,"html")

View File

@ -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'
});