Merge pull request #3367 from ether/master

Merge in 1.6.4
This commit is contained in:
John McLear 2018-04-07 11:05:58 +01:00 committed by GitHub
commit 4c16ac4b47
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 149 additions and 41 deletions

View File

@ -1,3 +1,17 @@
# 1.6.4
* SECURITY: exploitable /admin access - CVE-2018-9845
* SECURITY: DoS with pad exports - CVE-2018-9327
* SECURITY: Remote Code Execution - CVE-2018-9326
* SECURITY: Pad data leak - CVE-2018-9325
* Fix: Admin redirect URL
* Fix: Various script Fixes
* Fix: Various CSS/Style/Layout fixes
* NEW: Improved Pad contents readability
* NEW: Hook: onAccessCheck
* NEW: SESSIONKEY and APIKey customizable path
* NEW: checkPads script
* NEW: Support "cluster mode"
# 1.6.3
* SECURITY: Update ejs
* SECURITY: xss vulnerability when reading window.location.href

View File

@ -25,6 +25,10 @@ exports.createServer = function () {
else{
console.warn("Admin username and password not set in settings.json. To access admin please uncomment and edit 'users' in settings.json");
}
var env = process.env.NODE_ENV || 'development';
if(env !== 'production'){
console.warn("Etherpad is running in Development mode. This mode is slower for users and less secure than production mode. You should set the NODE_ENV environment variable to production by using: export NODE_ENV=production");
}
}
exports.restartServer = function () {

View File

@ -3,7 +3,7 @@ var apiLogger = log4js.getLogger("API");
var clientLogger = log4js.getLogger("client");
var formidable = require('formidable');
var apiHandler = require('../../handler/APIHandler');
var isVarName = require('is-var-name');
var isValidJSONPName = require('./isValidJsonPName');
//This is for making an api call, collecting all post information and passing it to the apiHandler
var apiCaller = function(req, res, fields) {
@ -19,7 +19,7 @@ var apiCaller = function(req, res, fields) {
apiLogger.info("RESPONSE, " + req.params.func + ", " + response);
//is this a jsonp call, if yes, add the function call
if(req.query.jsonp && isVarName(req.query.jsonp))
if(req.query.jsonp && isValidJSONPName.check(req.query.jsonp))
response = req.query.jsonp + "(" + response + ")";
res._____send(response);

View File

@ -2,6 +2,7 @@ var hasPadAccess = require("../../padaccess");
var settings = require('../../utils/Settings');
var exportHandler = require('../../handler/ExportHandler');
var importHandler = require('../../handler/ImportHandler');
var padManager = require("../../db/PadManager");
exports.expressCreateServer = function (hook_name, args, cb) {
args.app.get('/p/:pad/:rev?/export/:type', function(req, res, next) {
@ -22,14 +23,29 @@ exports.expressCreateServer = function (hook_name, args, cb) {
res.header("Access-Control-Allow-Origin", "*");
hasPadAccess(req, res, function() {
exportHandler.doExport(req, res, req.params.pad, req.params.type);
console.log('req.params.pad', req.params.pad);
padManager.doesPadExists(req.params.pad, function(err, exists)
{
if(!exists) {
return next();
}
exportHandler.doExport(req, res, req.params.pad, req.params.type);
});
});
});
//handle import requests
args.app.post('/p/:pad/import', function(req, res, next) {
hasPadAccess(req, res, function() {
importHandler.doImport(req, res, req.params.pad);
padManager.doesPadExists(req.params.pad, function(err, exists)
{
if(!exists) {
return next();
}
importHandler.doImport(req, res, req.params.pad);
});
});
});
}

View File

@ -0,0 +1,83 @@
const RESERVED_WORDS = [
'abstract',
'arguments',
'await',
'boolean',
'break',
'byte',
'case',
'catch',
'char',
'class',
'const',
'continue',
'debugger',
'default',
'delete',
'do',
'double',
'else',
'enum',
'eval',
'export',
'extends',
'false',
'final',
'finally',
'float',
'for',
'function',
'goto',
'if',
'implements',
'import',
'in',
'instanceof',
'int',
'interface',
'let',
'long',
'native',
'new',
'null',
'package',
'private',
'protected',
'public',
'return',
'short',
'static',
'super',
'switch',
'synchronized',
'this',
'throw',
'throws',
'transient',
'true',
'try',
'typeof',
'var',
'void',
'volatile',
'while',
'with',
'yield'
];
const regex = /^[a-zA-Z_$][0-9a-zA-Z_$]*(?:\[(?:".+"|\'.+\'|\d+)\])*?$/;
module.exports.check = function(inputStr) {
var isValid = true;
inputStr.split(".").forEach(function(part) {
if (!regex.test(part)) {
isValid = false;
}
if (RESERVED_WORDS.indexOf(part) !== -1) {
isValid = false;
}
});
return isValid;
}

View File

@ -20,7 +20,7 @@ exports.basicAuth = function (req, res, next) {
// Do not require auth for static paths and the API...this could be a bit brittle
if (req.path.match(/^\/(static|javascripts|pluginfw|api)/)) return cb(true);
if (req.path.indexOf('/admin') != 0) {
if (req.path.toLowerCase().indexOf('/admin') != 0) {
if (!settings.requireAuthentication) return cb(true);
if (!settings.requireAuthorization && req.session && req.session.user) return cb(true);
}
@ -38,7 +38,7 @@ exports.basicAuth = function (req, res, next) {
var password = userpass.join(':');
var fallback = function(success) {
if (success) return cb(true);
if (settings.users[username] != undefined && settings.users[username].password == password) {
if (settings.users[username] != undefined && settings.users[username].password === password) {
settings.users[username].username = username;
req.session.user = settings.users[username];
return cb(true);
@ -129,4 +129,3 @@ exports.expressConfigure = function (hook_name, args, cb) {
args.app.use(exports.basicAuth);
}

View File

@ -22,25 +22,18 @@ var ERR = require("async-stacktrace");
exports.getPadRaw = function(padId, callback){
async.waterfall([
function(cb){
// Get the Pad
db.findKeys("pad:"+padId, null, function(err,padcontent){
if(!err){
cb(err, padcontent);
}
})
db.get("pad:"+padId, cb);
},
function(padcontent,cb){
var records = ["pad:"+padId];
for (var i = 0; i <= padcontent.head; i++) {
records.push("pad:"+padId+":revs:" + i);
}
for (var i = 0; i <= padcontent.chatHead; i++) {
records.push("pad:"+padId+":chat:" + i);
}
// Get the Pad available content keys
db.findKeys("pad:"+padId+":*", null, function(err,records){
if(!err){
for (var key in padcontent) { records.push(padcontent[key]);}
cb(err, records);
}
})
},
function(records, cb){
var data = {};
async.forEachSeries(Object.keys(records), function(key, r){

View File

@ -24,7 +24,7 @@
"async" : "0.9.0",
"clean-css" : "3.4.19",
"uglify-js" : "2.6.2",
"formidable" : "1.0.17",
"formidable" : "1.2.1",
"log4js" : "0.6.35",
"cheerio" : "0.20.0",
"async-stacktrace" : "0.0.2",
@ -42,13 +42,12 @@
"channels" : "0.0.4",
"jsonminify" : "0.4.1",
"measured" : "1.1.0",
"mocha" : "2.4.5",
"supertest" : "1.2.0",
"is-var-name" : "1.0.0"
},
"mocha" : "5.0.5",
"supertest" : "3.0.0"
},
"bin": { "etherpad-lite": "./node/server.js" },
"devDependencies": {
"wd" : "0.3.11"
"wd" : "1.6.1"
},
"engines" : { "node" : ">=0.10.0",
"npm" : ">=1.0"
@ -56,6 +55,6 @@
"repository" : { "type" : "git",
"url" : "http://github.com/ether/etherpad-lite.git"
},
"version" : "1.6.3",
"version" : "1.6.4",
"license" : "Apache-2.0"
}

View File

@ -124,7 +124,7 @@ exports.getPackages = function (cb) {
var tmp = {};
tmp[data.name] = data;
flatten(tmp[undefined].dependencies);
flatten(tmp[data.name].dependencies);
cb(null, packages);
});
};