mirror of
https://github.com/ether/etherpad-lite.git
synced 2025-04-20 15:36:16 -04:00

This change is in preparation of the future async refactoring by Ray. It tries to extract as many changes in boolean conditions as possible, in order to make more evident identifying eventual logic bugs in the future work. This proved already useful in at least one case. BEWARE: this commit exposes an incoherency in the DB API, in which, depending on the driver used, some functions can return null or undefined. This condition will be externally fixed by the final commit in this series ("db/DB.js: prevent DB layer from returning undefined"). Until that commit, the code base may have some bugs.
245 lines
7.4 KiB
JavaScript
245 lines
7.4 KiB
JavaScript
/**
|
|
* The API Handler handles all API http requests
|
|
*/
|
|
|
|
/*
|
|
* 2011 Peter 'Pita' Martischka (Primary Technology Ltd)
|
|
*
|
|
* 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 absolutePaths = require('../utils/AbsolutePaths');
|
|
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 = absolutePaths.makeAbsolute(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");
|
|
}
|
|
|
|
// a list of all functions
|
|
var version = {};
|
|
|
|
version["1"] = Object.assign({},
|
|
{ "createGroup" : []
|
|
, "createGroupIfNotExistsFor" : ["groupMapper"]
|
|
, "deleteGroup" : ["groupID"]
|
|
, "listPads" : ["groupID"]
|
|
, "createPad" : ["padID", "text"]
|
|
, "createGroupPad" : ["groupID", "padName", "text"]
|
|
, "createAuthor" : ["name"]
|
|
, "createAuthorIfNotExistsFor": ["authorMapper" , "name"]
|
|
, "listPadsOfAuthor" : ["authorID"]
|
|
, "createSession" : ["groupID", "authorID", "validUntil"]
|
|
, "deleteSession" : ["sessionID"]
|
|
, "getSessionInfo" : ["sessionID"]
|
|
, "listSessionsOfGroup" : ["groupID"]
|
|
, "listSessionsOfAuthor" : ["authorID"]
|
|
, "getText" : ["padID", "rev"]
|
|
, "setText" : ["padID", "text"]
|
|
, "getHTML" : ["padID", "rev"]
|
|
, "setHTML" : ["padID", "html"]
|
|
, "getRevisionsCount" : ["padID"]
|
|
, "getLastEdited" : ["padID"]
|
|
, "deletePad" : ["padID"]
|
|
, "getReadOnlyID" : ["padID"]
|
|
, "setPublicStatus" : ["padID", "publicStatus"]
|
|
, "getPublicStatus" : ["padID"]
|
|
, "setPassword" : ["padID", "password"]
|
|
, "isPasswordProtected" : ["padID"]
|
|
, "listAuthorsOfPad" : ["padID"]
|
|
, "padUsersCount" : ["padID"]
|
|
}
|
|
);
|
|
|
|
version["1.1"] = Object.assign({}, version["1"],
|
|
{ "getAuthorName" : ["authorID"]
|
|
, "padUsers" : ["padID"]
|
|
, "sendClientsMessage" : ["padID", "msg"]
|
|
, "listAllGroups" : []
|
|
}
|
|
);
|
|
|
|
version["1.2"] = Object.assign({}, version["1.1"],
|
|
{ "checkToken" : []
|
|
}
|
|
);
|
|
|
|
version["1.2.1"] = Object.assign({}, version["1.2"],
|
|
{ "listAllPads" : []
|
|
}
|
|
);
|
|
|
|
version["1.2.7"] = Object.assign({}, version["1.2.1"],
|
|
{ "createDiffHTML" : ["padID", "startRev", "endRev"]
|
|
, "getChatHistory" : ["padID", "start", "end"]
|
|
, "getChatHead" : ["padID"]
|
|
}
|
|
);
|
|
|
|
version["1.2.8"] = Object.assign({}, version["1.2.7"],
|
|
{ "getAttributePool" : ["padID"]
|
|
, "getRevisionChangeset" : ["padID", "rev"]
|
|
}
|
|
);
|
|
|
|
version["1.2.9"] = Object.assign({}, version["1.2.8"],
|
|
{ "copyPad" : ["sourceID", "destinationID", "force"]
|
|
, "movePad" : ["sourceID", "destinationID", "force"]
|
|
}
|
|
);
|
|
|
|
version["1.2.10"] = Object.assign({}, version["1.2.9"],
|
|
{ "getPadID" : ["roID"]
|
|
}
|
|
);
|
|
|
|
version["1.2.11"] = Object.assign({}, version["1.2.10"],
|
|
{ "getSavedRevisionsCount" : ["padID"]
|
|
, "listSavedRevisions" : ["padID"]
|
|
, "saveRevision" : ["padID", "rev"]
|
|
, "restoreRevision" : ["padID", "rev"]
|
|
}
|
|
);
|
|
|
|
version["1.2.12"] = Object.assign({}, version["1.2.11"],
|
|
{ "appendChatMessage" : ["padID", "text", "authorID", "time"]
|
|
}
|
|
);
|
|
|
|
version["1.2.13"] = Object.assign({}, version["1.2.12"],
|
|
{ "appendText" : ["padID", "text"]
|
|
}
|
|
);
|
|
|
|
// set the latest available API version here
|
|
exports.latestApiVersion = '1.2.13';
|
|
|
|
// exports the versions so it can be used by the new Swagger endpoint
|
|
exports.version = version;
|
|
|
|
/**
|
|
* Handles a HTTP API call
|
|
* @param functionName the name of the called function
|
|
* @param fields the params of the called function
|
|
* @req express request object
|
|
* @res express response object
|
|
*/
|
|
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) {
|
|
isKnownApiVersion = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// 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
|
|
var isKnownFunctionname = false;
|
|
|
|
for (var knownFunctionname in version[apiVersion]) {
|
|
if (knownFunctionname == functionName) {
|
|
isKnownFunctionname = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// 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!
|
|
fields["apikey"] = fields["apikey"] || fields["api_key"];
|
|
|
|
if (fields["apikey"] !== apikey.trim()) {
|
|
res.statusCode = 401;
|
|
res.send({code: 4, message: "no or wrong API Key", data: null});
|
|
return;
|
|
}
|
|
|
|
// 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) {
|
|
fields["padName"] = padId;
|
|
callAPI(apiVersion, functionName, fields, req, res);
|
|
});
|
|
} else {
|
|
callAPI(apiVersion, functionName, fields, req, res);
|
|
}
|
|
}
|
|
|
|
// calls the api function
|
|
function callAPI(apiVersion, functionName, fields, req, res)
|
|
{
|
|
// 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) {
|
|
if (err == null) {
|
|
// no error happened, everything is fine
|
|
|
|
if (!data) {
|
|
data = null;
|
|
}
|
|
|
|
res.send({code: 0, message: "ok", data: data});
|
|
} 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});
|
|
} else {
|
|
// an unknown error happened
|
|
|
|
res.send({code: 2, message: "internal error", data: null});
|
|
ERR(err);
|
|
}
|
|
});
|
|
|
|
// call the api function
|
|
api[functionName].apply(this, functionParams);
|
|
}
|