prepare to async: trivial reformatting

This change is only cosmetic. Its aim is do make it easier to understand the
async changes that are going to be merged later on. It was extracted from the
original work from Ray Bellis.

To verify that nothing has changed, you can run the following command on each
file touched by this commit:
  npm install uglify-es
  diff --unified <(uglify-js --beautify bracketize <BEFORE.js>) <(uglify-js --beautify bracketize <AFTER.js>)



This is a complete script that does the same automatically (works from a
mercurial clone):

```bash
#!/usr/bin/env bash

set -eu

REVISION=<THIS_REVISION>

PARENT_REV=$(hg identify --rev "${REVISION}" --template '{p1rev}')
FILE_LIST=$(hg status --no-status --change ${REVISION})
UGLIFYJS="node_modules/uglify-es/bin/uglifyjs"

for FILE_NAME in ${FILE_LIST[@]}; do
  echo "Checking ${FILE_NAME}"
  diff --unified \
    <("${UGLIFYJS}" --beautify bracketize <(hg cat --rev "${PARENT_REV}" "${FILE_NAME}")) \
    <("${UGLIFYJS}" --beautify bracketize <(hg cat --rev "${REVISION}"   "${FILE_NAME}"))
done
```
This commit is contained in:
muxator 2019-02-08 23:20:57 +01:00
parent cc23bd18a4
commit 9497ee734f
33 changed files with 2706 additions and 2943 deletions

View file

@ -32,19 +32,17 @@ var apiHandlerLogger = log4js.getLogger('APIHandler');
//ensure we have an apikey
var apikey = null;
var apikeyFilename = absolutePaths.makeAbsolute(argv.apikey || "./APIKEY.txt");
try
{
try {
apikey = fs.readFileSync(apikeyFilename,"utf8");
apiHandlerLogger.info(`Api key file read from: "${apikeyFilename}"`);
}
catch(e)
{
} catch(e) {
apiHandlerLogger.info(`Api key file "${apikeyFilename}" not found. Creating with random contents.`);
apikey = randomString(32);
fs.writeFileSync(apikeyFilename,apikey,"utf8");
}
//a list of all functions
// a list of all functions
var version = {};
version["1"] = Object.assign({},
@ -156,106 +154,92 @@ exports.handle = function(apiVersion, functionName, fields, req, res)
{
//check if this is a valid apiversion
var isKnownApiVersion = false;
for(var knownApiVersion in version)
{
if(knownApiVersion == apiVersion)
{
for (var knownApiVersion in version) {
if (knownApiVersion == apiVersion) {
isKnownApiVersion = true;
break;
}
}
//say goodbye if this is an unknown API version
if(!isKnownApiVersion)
{
// say goodbye if this is an unknown API version
if (!isKnownApiVersion) {
res.statusCode = 404;
res.send({code: 3, message: "no such api version", data: null});
return;
}
//check if this is a valid function name
// check if this is a valid function name
var isKnownFunctionname = false;
for(var knownFunctionname in version[apiVersion])
{
if(knownFunctionname == functionName)
{
for (var knownFunctionname in version[apiVersion]) {
if (knownFunctionname == functionName) {
isKnownFunctionname = true;
break;
}
}
//say goodbye if this is a unknown function
if(!isKnownFunctionname)
{
// say goodbye if this is an unknown function
if (!isKnownFunctionname) {
res.send({code: 3, message: "no such function", data: null});
return;
}
//check the api key!
// check the api key!
fields["apikey"] = fields["apikey"] || fields["api_key"];
if(fields["apikey"] != apikey.trim())
{
if (fields["apikey"] != apikey.trim()) {
res.statusCode = 401;
res.send({code: 4, message: "no or wrong API Key", data: null});
return;
}
//sanitize any pad id's before continuing
if(fields["padID"])
{
padManager.sanitizePadId(fields["padID"], function(padId)
{
// sanitize any padIDs before continuing
if (fields["padID"]) {
padManager.sanitizePadId(fields["padID"], function(padId) {
fields["padID"] = padId;
callAPI(apiVersion, functionName, fields, req, res);
});
}
else if(fields["padName"])
{
padManager.sanitizePadId(fields["padName"], function(padId)
{
} else if (fields["padName"]) {
padManager.sanitizePadId(fields["padName"], function(padId) {
fields["padName"] = padId;
callAPI(apiVersion, functionName, fields, req, res);
});
}
else
{
} else {
callAPI(apiVersion, functionName, fields, req, res);
}
}
//calls the api function
// calls the api function
function callAPI(apiVersion, functionName, fields, req, res)
{
//put the function parameters in an array
// put the function parameters in an array
var functionParams = version[apiVersion][functionName].map(function (field) {
return fields[field]
})
});
//add a callback function to handle the response
functionParams.push(function(err, data)
{
// no error happend, everything is fine
if(err == null)
{
if(!data)
// add a callback function to handle the response
functionParams.push(function(err, data) {
if (err == null) {
// no error happened, everything is fine
if (!data) {
data = null;
}
res.send({code: 0, message: "ok", data: data});
}
// parameters were wrong and the api stopped execution, pass the error
else if(err.name == "apierror")
{
} else if (err.name == "apierror") {
// parameters were wrong and the api stopped execution, pass the error
res.send({code: 1, message: err.message, data: null});
}
//an unknown error happend
else
{
} else {
// an unknown error happened
res.send({code: 2, message: "internal error", data: null});
ERR(err);
}
});
//call the api function
// call the api function
api[functionName].apply(this, functionParams);
}

View file

@ -32,13 +32,15 @@ var TidyHtml = require('../utils/TidyHtml');
var convertor = null;
//load abiword only if its enabled
if(settings.abiword != null)
// load abiword only if it is enabled
if (settings.abiword != null) {
convertor = require("../utils/Abiword");
}
// Use LibreOffice if an executable has been defined in the settings
if(settings.soffice != null)
if (settings.soffice != null) {
convertor = require("../utils/LibreOffice");
}
const tempDirectory = os.tmpdir();
@ -53,62 +55,55 @@ exports.doExport = function(req, res, padId, type)
hooks.aCallFirst("exportFileName", padId,
function(err, hookFileName){
// if fileName is set then set it to the padId, note that fileName is returned as an array.
if(hookFileName.length) fileName = hookFileName;
if (hookFileName.length) {
fileName = hookFileName;
}
//tell the browser that this is a downloadable file
// tell the browser that this is a downloadable file
res.attachment(fileName + "." + type);
//if this is a plain text export, we can do this directly
// if this is a plain text export, we can do this directly
// We have to over engineer this because tabs are stored as attributes and not plain text
if(type == "etherpad"){
exportEtherpad.getPadRaw(padId, function(err, pad){
if(!err){
if (type == "etherpad") {
exportEtherpad.getPadRaw(padId, function(err, pad) {
if (!err) {
res.send(pad);
// return;
}
});
}
else if(type == "txt")
{
exporttxt.getPadTXTDocument(padId, req.params.rev, function(err, txt)
{
if(!err) {
} else if (type == "txt") {
exporttxt.getPadTXTDocument(padId, req.params.rev, function(err, txt) {
if (!err) {
res.send(txt);
}
});
}
else
{
} else {
var html;
var randNum;
var srcFile, destFile;
async.series([
//render the html document
function(callback)
{
exporthtml.getPadHTMLDocument(padId, req.params.rev, function(err, _html)
{
if(ERR(err, callback)) return;
// render the html document
function(callback) {
exporthtml.getPadHTMLDocument(padId, req.params.rev, function(err, _html) {
if (ERR(err, callback)) return;
html = _html;
callback();
});
},
//decide what to do with the html export
function(callback)
{
//if this is a html export, we can send this from here directly
if(type == "html")
{
// decide what to do with the html export
function(callback) {
// if this is a html export, we can send this from here directly
if (type == "html") {
// do any final changes the plugin might want to make
hooks.aCallFirst("exportHTMLSend", html, function(err, newHTML){
if(newHTML.length) html = newHTML;
hooks.aCallFirst("exportHTMLSend", html, function(err, newHTML) {
if (newHTML.length) html = newHTML;
res.send(html);
callback("stop");
});
}
else //write the html export to a file
{
} else {
// write the html export to a file
randNum = Math.floor(Math.random()*0xFFFFFFFF);
srcFile = tempDirectory + "/etherpad_export_" + randNum + ".html";
fs.writeFile(srcFile, html, callback);
@ -116,64 +111,56 @@ exports.doExport = function(req, res, padId, type)
},
// Tidy up the exported HTML
function(callback)
{
//ensure html can be collected by the garbage collector
function(callback) {
// ensure html can be collected by the garbage collector
html = null;
TidyHtml.tidy(srcFile, callback);
},
//send the convert job to the convertor (abiword, libreoffice, ..)
function(callback)
{
// send the convert job to the convertor (abiword, libreoffice, ..)
function(callback) {
destFile = tempDirectory + "/etherpad_export_" + randNum + "." + type;
// Allow plugins to overwrite the convert in export process
hooks.aCallAll("exportConvert", {srcFile: srcFile, destFile: destFile, req: req, res: res}, function(err, result){
if(!err && result.length > 0){
hooks.aCallAll("exportConvert", { srcFile: srcFile, destFile: destFile, req: req, res: res }, function(err, result) {
if (!err && result.length > 0) {
// console.log("export handled by plugin", destFile);
handledByPlugin = true;
callback();
}else{
} else {
convertor.convertFile(srcFile, destFile, type, callback);
}
});
},
//send the file
function(callback)
{
// send the file
function(callback) {
res.sendFile(destFile, null, callback);
},
//clean up temporary files
function(callback)
{
// clean up temporary files
function(callback) {
async.parallel([
function(callback)
{
function(callback) {
fs.unlink(srcFile, callback);
},
function(callback)
{
//100ms delay to accomidate for slow windows fs
if(os.type().indexOf("Windows") > -1)
{
setTimeout(function()
{
function(callback) {
// 100ms delay to accommodate for slow windows fs
if (os.type().indexOf("Windows") > -1) {
setTimeout(function() {
fs.unlink(destFile, callback);
}, 100);
}
else
{
} else {
fs.unlink(destFile, callback);
}
}
], callback);
}
], function(err)
{
if(err && err != "stop") ERR(err);
],
function(err) {
if (err && err != "stop") ERR(err);
})
}
}

View file

@ -37,29 +37,30 @@ var ERR = require("async-stacktrace")
var convertor = null;
var exportExtension = "htm";
//load abiword only if its enabled and if soffice is disabled
if(settings.abiword != null && settings.soffice === null)
// load abiword only if it is enabled and if soffice is disabled
if (settings.abiword != null && settings.soffice === null) {
convertor = require("../utils/Abiword");
}
//load soffice only if its enabled
if(settings.soffice != null) {
// load soffice only if it is enabled
if (settings.soffice != null) {
convertor = require("../utils/LibreOffice");
exportExtension = "html";
}
const tmpDirectory = os.tmpdir();
/**
* do a requested import
*/
*/
exports.doImport = function(req, res, padId)
{
var apiLogger = log4js.getLogger("ImportHandler");
//pipe to a file
//convert file to html via abiword or soffice
//set html in the pad
// pipe to a file
// convert file to html via abiword or soffice
// set html in the pad
var srcFile, destFile
, pad
, text
@ -68,69 +69,74 @@ exports.doImport = function(req, res, padId)
, useConvertor;
var randNum = Math.floor(Math.random()*0xFFFFFFFF);
// setting flag for whether to use convertor or not
useConvertor = (convertor != null);
async.series([
//save the uploaded file to /tmp
// save the uploaded file to /tmp
function(callback) {
var form = new formidable.IncomingForm();
form.keepExtensions = true;
form.uploadDir = tmpDirectory;
form.parse(req, function(err, fields, files) {
//the upload failed, stop at this point
if(err || files.file === undefined) {
if(err) console.warn("Uploading Error: " + err.stack);
form.parse(req, function(err, fields, files) {
if (err || files.file === undefined) {
// the upload failed, stop at this point
if (err) {
console.warn("Uploading Error: " + err.stack);
}
callback("uploadFailed");
return;
}
//everything ok, continue
//save the path of the uploaded file
// everything ok, continue
// save the path of the uploaded file
srcFile = files.file.path;
callback();
});
},
//ensure this is a file ending we know, else we change the file ending to .txt
//this allows us to accept source code files like .c or .java
// ensure this is a file ending we know, else we change the file ending to .txt
// this allows us to accept source code files like .c or .java
function(callback) {
var fileEnding = path.extname(srcFile).toLowerCase()
, knownFileEndings = [".txt", ".doc", ".docx", ".pdf", ".odt", ".html", ".htm", ".etherpad", ".rtf"]
, fileEndingKnown = (knownFileEndings.indexOf(fileEnding) > -1);
//if the file ending is known, continue as normal
if(fileEndingKnown) {
// if the file ending is known, continue as normal
if (fileEndingKnown) {
callback();
return;
}
//we need to rename this file with a .txt ending
if(settings.allowUnknownFileEnds === true){
// we need to rename this file with a .txt ending
if (settings.allowUnknownFileEnds === true) {
var oldSrcFile = srcFile;
srcFile = path.join(path.dirname(srcFile),path.basename(srcFile, fileEnding)+".txt");
srcFile = path.join(path.dirname(srcFile), path.basename(srcFile, fileEnding) + ".txt");
fs.rename(oldSrcFile, srcFile, callback);
}else{
} else {
console.warn("Not allowing unknown file type to be imported", fileEnding);
callback("uploadFailed");
}
},
function(callback){
function(callback) {
destFile = path.join(tmpDirectory, "etherpad_import_" + randNum + "." + exportExtension);
// Logic for allowing external Import Plugins
hooks.aCallAll("import", {srcFile: srcFile, destFile: destFile}, function(err, result){
if(ERR(err, callback)) return callback();
if(result.length > 0){ // This feels hacky and wrong..
hooks.aCallAll("import", { srcFile: srcFile, destFile: destFile }, function(err, result) {
if (ERR(err, callback)) return callback();
if (result.length > 0) { // This feels hacky and wrong..
importHandledByPlugin = true;
}
callback();
});
},
function(callback) {
var fileEnding = path.extname(srcFile).toLowerCase()
var fileIsNotEtherpad = (fileEnding !== ".etherpad");
@ -141,23 +147,24 @@ exports.doImport = function(req, res, padId)
return;
}
// we do this here so we can see if the pad has quit ea few edits
padManager.getPad(padId, function(err, _pad){
// we do this here so we can see if the pad has quite a few edits
padManager.getPad(padId, function(err, _pad) {
var headCount = _pad.head;
if(headCount >= 10){
apiLogger.warn("Direct database Import attempt of a pad that already has content, we wont be doing this")
if (headCount >= 10) {
apiLogger.warn("Direct database Import attempt of a pad that already has content, we wont be doing this");
return callback("padHasData");
}
fs.readFile(srcFile, "utf8", function(err, _text){
fs.readFile(srcFile, "utf8", function(err, _text) {
directDatabaseAccess = true;
importEtherpad.setPadRaw(padId, _text, function(err){
importEtherpad.setPadRaw(padId, _text, function(err) {
callback();
});
});
});
},
//convert file to html
// convert file to html if necessary
function(callback) {
if (importHandledByPlugin || directDatabaseAccess) {
callback();
@ -168,18 +175,20 @@ exports.doImport = function(req, res, padId)
var fileEnding = path.extname(srcFile).toLowerCase();
var fileIsHTML = (fileEnding === ".html" || fileEnding === ".htm");
var fileIsTXT = (fileEnding === ".txt");
if (fileIsTXT) useConvertor = false; // Don't use convertor for text files
// See https://github.com/ether/etherpad-lite/issues/2572
if (fileIsHTML || (useConvertor === false)) {
// if no convertor only rename
fs.rename(srcFile, destFile, callback);
return;
}
convertor.convertFile(srcFile, destFile, exportExtension, function(err) {
//catch convert errors
if(err) {
// catch convert errors
if (err) {
console.warn("Converting Error:", err);
return callback("convertFailed");
}
@ -187,7 +196,7 @@ exports.doImport = function(req, res, padId)
callback();
});
},
function(callback) {
if (useConvertor || directDatabaseAccess) {
callback();
@ -216,17 +225,17 @@ exports.doImport = function(req, res, padId)
callback();
});
},
//get the pad object
// get the pad object
function(callback) {
padManager.getPad(padId, function(err, _pad){
if(ERR(err, callback)) return;
padManager.getPad(padId, function(err, _pad) {
if (ERR(err, callback)) return;
pad = _pad;
callback();
});
},
//read the text
// read the text
function(callback) {
if (directDatabaseAccess) {
callback();
@ -234,43 +243,46 @@ exports.doImport = function(req, res, padId)
return;
}
fs.readFile(destFile, "utf8", function(err, _text){
if(ERR(err, callback)) return;
fs.readFile(destFile, "utf8", function(err, _text) {
if (ERR(err, callback)) return;
text = _text;
// Title needs to be stripped out else it appends it to the pad..
text = text.replace("<title>", "<!-- <title>");
text = text.replace("</title>","</title>-->");
//node on windows has a delay on releasing of the file lock.
//We add a 100ms delay to work around this
if(os.type().indexOf("Windows") > -1){
// node on windows has a delay on releasing of the file lock.
// We add a 100ms delay to work around this
if (os.type().indexOf("Windows") > -1) {
setTimeout(function() {callback();}, 100);
} else {
callback();
}
});
},
//change text of the pad and broadcast the changeset
// change text of the pad and broadcast the changeset
function(callback) {
if(!directDatabaseAccess){
if (!directDatabaseAccess) {
var fileEnding = path.extname(srcFile).toLowerCase();
if (importHandledByPlugin || useConvertor || fileEnding == ".htm" || fileEnding == ".html") {
importHtml.setPadHTML(pad, text, function(e){
if(e) apiLogger.warn("Error importing, possibly caused by malformed HTML");
if (e) {
apiLogger.warn("Error importing, possibly caused by malformed HTML");
}
});
} else {
pad.setText(text);
}
}
// Load the Pad into memory then brodcast updates to all clients
// Load the Pad into memory then broadcast updates to all clients
padManager.unloadPad(padId);
padManager.getPad(padId, function(err, _pad){
padManager.getPad(padId, function(err, _pad) {
var pad = _pad;
padManager.unloadPad(padId);
// direct Database Access means a pad user should perform a switchToPad
// and not attempt to recieve updated pad data..
// and not attempt to receive updated pad data
if (directDatabaseAccess) {
callback();
@ -283,8 +295,8 @@ exports.doImport = function(req, res, padId)
});
},
//clean up temporary files
// clean up temporary files
function(callback) {
if (directDatabaseAccess) {
callback();
@ -308,17 +320,16 @@ exports.doImport = function(req, res, padId)
}
], function(err) {
var status = "ok";
//check for known errors and replace the status
if(err == "uploadFailed" || err == "convertFailed" || err == "padHasData")
{
// check for known errors and replace the status
if (err == "uploadFailed" || err == "convertFailed" || err == "padHasData") {
status = err;
err = null;
}
ERR(err);
//close the connection
// close the connection
res.send(
"<head> \
<script type='text/javascript' src='../../static/js/jquery.js'></script> \
@ -331,4 +342,3 @@ exports.doImport = function(req, res, padId)
);
});
}

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,5 @@
/**
* This is the Socket.IO Router. It routes the Messages between the
* This is the Socket.IO Router. It routes the Messages between the
* components of the Server. The components are at the moment: pad and timeslider
*/
@ -31,20 +31,20 @@ var settings = require('../utils/Settings');
* Saves all components
* key is the component name
* value is the component module
*/
*/
var components = {};
var socket;
/**
* adds a component
*/
exports.addComponent = function(moduleName, module)
{
//save the component
// save the component
components[moduleName] = module;
//give the module the socket
// give the module the socket
module.setSocketIO(socket);
}
@ -52,57 +52,55 @@ exports.addComponent = function(moduleName, module)
* sets the socket.io and adds event functions for routing
*/
exports.setSocketIO = function(_socket) {
//save this socket internaly
// save this socket internaly
socket = _socket;
socket.sockets.on('connection', function(client)
{
// Broken: See http://stackoverflow.com/questions/4647348/send-message-to-specific-client-with-socket-io-and-node-js
// Fixed by having a persistant object, ideally this would actually be in the database layer
// TODO move to database layer
if(settings.trustProxy && client.handshake.headers['x-forwarded-for'] !== undefined){
if (settings.trustProxy && client.handshake.headers['x-forwarded-for'] !== undefined) {
remoteAddress[client.id] = client.handshake.headers['x-forwarded-for'];
}
else{
} else {
remoteAddress[client.id] = client.handshake.address;
}
var clientAuthorized = false;
//wrap the original send function to log the messages
// wrap the original send function to log the messages
client._send = client.send;
client.send = function(message) {
messageLogger.debug("to " + client.id + ": " + stringifyWithoutPassword(message));
client._send(message);
}
//tell all components about this connect
for(var i in components) {
components[i].handleConnect(client);
}
client.on('message', function(message)
{
if(message.protocolVersion && message.protocolVersion != 2) {
// tell all components about this connect
for (var i in components) {
components[i].handleConnect(client);
}
client.on('message', function(message) {
if (message.protocolVersion && message.protocolVersion != 2) {
messageLogger.warn("Protocolversion header is not correct:" + stringifyWithoutPassword(message));
return;
}
//client is authorized, everything ok
if(clientAuthorized) {
if (clientAuthorized) {
// client is authorized, everything ok
handleMessage(client, message);
} else { //try to authorize the client
if(message.padId !== undefined && message.sessionID !== undefined && message.token !== undefined && message.password !== undefined) {
} else {
// try to authorize the client
if (message.padId !== undefined && message.sessionID !== undefined && message.token !== undefined && message.password !== undefined) {
var checkAccessCallback = function(err, statusObject) {
ERR(err);
//access was granted, mark the client as authorized and handle the message
if(statusObject.accessStatus == "grant") {
if (statusObject.accessStatus == "grant") {
// access was granted, mark the client as authorized and handle the message
clientAuthorized = true;
handleMessage(client, message);
}
//no access, send the client a message that tell him why
else {
} else {
// no access, send the client a message that tells him why
messageLogger.warn("Authentication try failed:" + stringifyWithoutPassword(message));
client.json.send({accessStatus: statusObject.accessStatus});
}
@ -110,57 +108,55 @@ exports.setSocketIO = function(_socket) {
if (message.padId.indexOf("r.") === 0) {
readOnlyManager.getPadId(message.padId, function(err, value) {
ERR(err);
securityManager.checkAccess (value, message.sessionID, message.token, message.password, checkAccessCallback);
securityManager.checkAccess(value, message.sessionID, message.token, message.password, checkAccessCallback);
});
} else {
//this message has everything to try an authorization
// this message has everything to try an authorization
securityManager.checkAccess (message.padId, message.sessionID, message.token, message.password, checkAccessCallback);
}
} else { //drop message
} else {
// drop message
messageLogger.warn("Dropped message cause of bad permissions:" + stringifyWithoutPassword(message));
}
}
});
client.on('disconnect', function()
{
//tell all components about this disconnect
for(var i in components)
{
client.on('disconnect', function() {
// tell all components about this disconnect
for (var i in components) {
components[i].handleDisconnect(client);
}
});
});
}
//try to handle the message of this client
// try to handle the message of this client
function handleMessage(client, message)
{
if(message.component && components[message.component]) {
//check if component is registered in the components array
if(components[message.component]) {
if (message.component && components[message.component]) {
// check if component is registered in the components array
if (components[message.component]) {
messageLogger.debug("from " + client.id + ": " + stringifyWithoutPassword(message));
components[message.component].handleMessage(client, message);
}
} else {
messageLogger.error("Can't route the message:" + stringifyWithoutPassword(message));
}
}
}
//returns a stringified representation of a message, removes the password
//this ensures there are no passwords in the log
// returns a stringified representation of a message, removes the password
// this ensures there are no passwords in the log
function stringifyWithoutPassword(message)
{
var newMessage = {};
for(var i in message)
{
if(i == "password" && message[i] != null)
for (var i in message) {
if (i == "password" && message[i] != null) {
newMessage["password"] = "xxx";
else
newMessage[i]=message[i];
} else {
newMessage[i] = message[i];
}
}
return JSON.stringify(newMessage);
}