db/SessionManager.js: mostly converted to Promises
parent
16c4c33f49
commit
a875ca6c30
|
@ -21,160 +21,106 @@
|
|||
var ERR = require("async-stacktrace");
|
||||
var customError = require("../utils/customError");
|
||||
var randomString = require("../utils/randomstring");
|
||||
var db = require("./DB").db;
|
||||
var async = require("async");
|
||||
var db = require("./DB");
|
||||
var groupManager = require("./GroupManager");
|
||||
var authorManager = require("./AuthorManager");
|
||||
const thenify = require("thenify").withCallback;
|
||||
|
||||
exports.doesSessionExist = thenify(function(sessionID, callback)
|
||||
exports.doesSessionExist = async function(sessionID)
|
||||
{
|
||||
//check if the database entry of this session exists
|
||||
db.get("session:" + sessionID, function (err, session)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
callback(null, session != null);
|
||||
});
|
||||
});
|
||||
let session = await db.get("session:" + sessionID);
|
||||
return (session !== null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new session between an author and a group
|
||||
*/
|
||||
exports.createSession = thenify(function(groupID, authorID, validUntil, callback)
|
||||
exports.createSession = async function(groupID, authorID, validUntil)
|
||||
{
|
||||
var sessionID;
|
||||
// check if the group exists
|
||||
let groupExists = await groupManager.doesGroupExist(groupID);
|
||||
if (!groupExists) {
|
||||
throw new customError("groupID does not exist", "apierror");
|
||||
}
|
||||
|
||||
async.series([
|
||||
// check if the group exists
|
||||
function(callback)
|
||||
{
|
||||
groupManager.doesGroupExist(groupID, function(err, exists)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
// check if the author exists
|
||||
let authorExists = await authorManager.doesAuthorExist(authorID);
|
||||
if (!authorExists) {
|
||||
throw new customError("authorID does not exist", "apierror");
|
||||
}
|
||||
|
||||
// group does not exist
|
||||
if (exists == false) {
|
||||
callback(new customError("groupID does not exist", "apierror"));
|
||||
} else {
|
||||
// everything is fine, continue
|
||||
callback();
|
||||
}
|
||||
});
|
||||
},
|
||||
// try to parse validUntil if it's not a number
|
||||
if (typeof validUntil !== "number") {
|
||||
validUntil = parseInt(validUntil);
|
||||
}
|
||||
|
||||
// check if the author exists
|
||||
function(callback)
|
||||
{
|
||||
authorManager.doesAuthorExists(authorID, function(err, exists)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
// check it's a valid number
|
||||
if (isNaN(validUntil)) {
|
||||
throw new customError("validUntil is not a number", "apierror");
|
||||
}
|
||||
|
||||
if (exists == false) {
|
||||
// author does not exist
|
||||
callback(new customError("authorID does not exist", "apierror"));
|
||||
} else {
|
||||
// everything is fine, continue
|
||||
callback();
|
||||
}
|
||||
});
|
||||
},
|
||||
// ensure this is not a negative number
|
||||
if (validUntil < 0) {
|
||||
throw new customError("validUntil is a negative number", "apierror");
|
||||
}
|
||||
|
||||
// check validUntil and create the session db entry
|
||||
function(callback)
|
||||
{
|
||||
// check if rev is a number
|
||||
if (typeof validUntil != "number")
|
||||
{
|
||||
// try to parse the number
|
||||
if (isNaN(parseInt(validUntil))) {
|
||||
callback(new customError("validUntil is not a number", "apierror"));
|
||||
return;
|
||||
}
|
||||
// ensure this is not a float value
|
||||
if (!is_int(validUntil)) {
|
||||
throw new customError("validUntil is a float value", "apierror");
|
||||
}
|
||||
|
||||
validUntil = parseInt(validUntil);
|
||||
}
|
||||
// check if validUntil is in the future
|
||||
if (validUntil < Math.floor(Date.now() / 1000)) {
|
||||
throw new customError("validUntil is in the past", "apierror");
|
||||
}
|
||||
|
||||
// ensure this is not a negative number
|
||||
if (validUntil < 0) {
|
||||
callback(new customError("validUntil is a negative number", "apierror"));
|
||||
return;
|
||||
}
|
||||
// generate sessionID
|
||||
let sessionID = "s." + randomString(16);
|
||||
|
||||
// ensure this is not a float value
|
||||
if (!is_int(validUntil)) {
|
||||
callback(new customError("validUntil is a float value", "apierror"));
|
||||
return;
|
||||
}
|
||||
// set the session into the database
|
||||
await db.set("session:" + sessionID, {"groupID": groupID, "authorID": authorID, "validUntil": validUntil});
|
||||
|
||||
// check if validUntil is in the future
|
||||
if (Math.floor(Date.now()/1000) > validUntil) {
|
||||
callback(new customError("validUntil is in the past", "apierror"));
|
||||
return;
|
||||
}
|
||||
// get the entry
|
||||
let group2sessions = await db.get("group2sessions:" + groupID);
|
||||
|
||||
// generate sessionID
|
||||
sessionID = "s." + randomString(16);
|
||||
/*
|
||||
* In some cases, the db layer could return "undefined" as well as "null".
|
||||
* Thus, it is not possible to perform strict null checks on group2sessions.
|
||||
* In a previous version of this code, a strict check broke session
|
||||
* management.
|
||||
*
|
||||
* See: https://github.com/ether/etherpad-lite/issues/3567#issuecomment-468613960
|
||||
*/
|
||||
if (!group2sessions || !group2sessions.sessionIDs) {
|
||||
// the entry doesn't exist so far, let's create it
|
||||
group2sessions = {sessionIDs : {}};
|
||||
}
|
||||
|
||||
// set the session into the database
|
||||
db.set("session:" + sessionID, {"groupID": groupID, "authorID": authorID, "validUntil": validUntil});
|
||||
// add the entry for this session
|
||||
group2sessions.sessionIDs[sessionID] = 1;
|
||||
|
||||
callback();
|
||||
},
|
||||
// save the new element back
|
||||
await db.set("group2sessions:" + groupID, group2sessions);
|
||||
|
||||
// set the group2sessions entry
|
||||
function(callback)
|
||||
{
|
||||
// get the entry
|
||||
db.get("group2sessions:" + groupID, function(err, group2sessions)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
// get the author2sessions entry
|
||||
let author2sessions = await db.get("author2sessions:" + authorID);
|
||||
|
||||
if (group2sessions == null || group2sessions.sessionIDs == null) {
|
||||
// the entry doesn't exist so far, let's create it
|
||||
group2sessions = {sessionIDs : {}};
|
||||
}
|
||||
if (author2sessions == null || author2sessions.sessionIDs == null) {
|
||||
// the entry doesn't exist so far, let's create it
|
||||
author2sessions = {sessionIDs : {}};
|
||||
}
|
||||
|
||||
// add the entry for this session
|
||||
group2sessions.sessionIDs[sessionID] = 1;
|
||||
// add the entry for this session
|
||||
author2sessions.sessionIDs[sessionID] = 1;
|
||||
|
||||
// save the new element back
|
||||
db.set("group2sessions:" + groupID, group2sessions);
|
||||
//save the new element back
|
||||
await db.set("author2sessions:" + authorID, author2sessions);
|
||||
|
||||
callback();
|
||||
});
|
||||
},
|
||||
|
||||
// set the author2sessions entry
|
||||
function(callback)
|
||||
{
|
||||
// get the entry
|
||||
db.get("author2sessions:" + authorID, function(err, author2sessions)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
if (author2sessions == null || author2sessions.sessionIDs == null) {
|
||||
// the entry doesn't exist so far, let's create it
|
||||
author2sessions = {sessionIDs : {}};
|
||||
}
|
||||
|
||||
// add the entry for this session
|
||||
author2sessions.sessionIDs[sessionID] = 1;
|
||||
|
||||
//save the new element back
|
||||
db.set("author2sessions:" + authorID, author2sessions);
|
||||
|
||||
callback();
|
||||
});
|
||||
}
|
||||
], function(err)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
// return error and sessionID
|
||||
callback(null, {sessionID: sessionID});
|
||||
})
|
||||
});
|
||||
return { sessionID };
|
||||
}
|
||||
|
||||
// @TODO once external dependencies are using Promises
|
||||
exports.getSessionInfo = thenify(function(sessionID, callback)
|
||||
{
|
||||
// check if the database entry of this session exists
|
||||
|
@ -195,160 +141,86 @@ exports.getSessionInfo = thenify(function(sessionID, callback)
|
|||
/**
|
||||
* Deletes a session
|
||||
*/
|
||||
exports.deleteSession = thenify(function(sessionID, callback)
|
||||
exports.deleteSession = async function(sessionID)
|
||||
{
|
||||
var authorID, groupID;
|
||||
var group2sessions, author2sessions;
|
||||
// ensure that the session exists
|
||||
let session = await db.get("session:" + sessionID);
|
||||
if (session == null) {
|
||||
throw new customError("sessionID does not exist", "apierror");
|
||||
}
|
||||
|
||||
async.series([
|
||||
function(callback)
|
||||
{
|
||||
// get the session entry
|
||||
db.get("session:" + sessionID, function (err, session)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
// everything is fine, use the sessioninfos
|
||||
let groupID = session.groupID;
|
||||
let authorID = session.authorID;
|
||||
|
||||
if (session == null) {
|
||||
// session does not exist
|
||||
callback(new customError("sessionID does not exist", "apierror"))
|
||||
} else {
|
||||
// everything is fine, use the sessioninfos
|
||||
authorID = session.authorID;
|
||||
groupID = session.groupID;
|
||||
// get the group2sessions and author2sessions entries
|
||||
let group2sessions = await db.get("group2sessions:" + groupID);
|
||||
let author2sessions = await db.get("author2sessions:" + authorID);
|
||||
|
||||
callback();
|
||||
}
|
||||
});
|
||||
},
|
||||
// remove the session
|
||||
await db.remove("session:" + sessionID);
|
||||
|
||||
// get the group2sessions entry
|
||||
function(callback)
|
||||
{
|
||||
db.get("group2sessions:" + groupID, function (err, _group2sessions)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
group2sessions = _group2sessions;
|
||||
callback();
|
||||
});
|
||||
},
|
||||
// remove session from group2sessions
|
||||
if (group2sessions != null) { // Maybe the group was already deleted
|
||||
delete group2sessions.sessionIDs[sessionID];
|
||||
await db.set("group2sessions:" + groupID, group2sessions);
|
||||
}
|
||||
|
||||
// get the author2sessions entry
|
||||
function(callback)
|
||||
{
|
||||
db.get("author2sessions:" + authorID, function (err, _author2sessions)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
author2sessions = _author2sessions;
|
||||
callback();
|
||||
});
|
||||
},
|
||||
// remove session from author2sessions
|
||||
if (author2sessions != null) { // Maybe the author was already deleted
|
||||
delete author2sessions.sessionIDs[sessionID];
|
||||
await db.set("author2sessions:" + authorID, author2sessions);
|
||||
}
|
||||
}
|
||||
|
||||
// remove the values from the database
|
||||
function(callback)
|
||||
{
|
||||
//remove the session
|
||||
db.remove("session:" + sessionID);
|
||||
|
||||
// remove session from group2sessions
|
||||
if(group2sessions != null) { // Maybe the group was already deleted
|
||||
delete group2sessions.sessionIDs[sessionID];
|
||||
db.set("group2sessions:" + groupID, group2sessions);
|
||||
}
|
||||
|
||||
// remove session from author2sessions
|
||||
if(author2sessions != null) { // Maybe the author was already deleted
|
||||
delete author2sessions.sessionIDs[sessionID];
|
||||
db.set("author2sessions:" + authorID, author2sessions);
|
||||
}
|
||||
|
||||
callback();
|
||||
}
|
||||
], function(err)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
callback();
|
||||
})
|
||||
});
|
||||
|
||||
exports.listSessionsOfGroup = thenify(function(groupID, callback)
|
||||
exports.listSessionsOfGroup = async function(groupID)
|
||||
{
|
||||
groupManager.doesGroupExist(groupID, function(err, exists)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
// check that the group exists
|
||||
let exists = await groupManager.doesGroupExist(groupID);
|
||||
if (!exists) {
|
||||
throw new customError("groupID does not exist", "apierror");
|
||||
}
|
||||
|
||||
if (exists == false) {
|
||||
// group does not exist
|
||||
callback(new customError("groupID does not exist", "apierror"));
|
||||
} else {
|
||||
// everything is fine, continue
|
||||
listSessionsWithDBKey("group2sessions:" + groupID, callback);
|
||||
}
|
||||
});
|
||||
});
|
||||
let sessions = await listSessionsWithDBKey("group2sessions:" + groupID);
|
||||
return sessions;
|
||||
}
|
||||
|
||||
exports.listSessionsOfAuthor = thenify(function(authorID, callback)
|
||||
exports.listSessionsOfAuthor = async function(authorID)
|
||||
{
|
||||
authorManager.doesAuthorExists(authorID, function(err, exists)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
// check that the author exists
|
||||
let exists = await authorManager.doesAuthorExist(authorID)
|
||||
if (!exists) {
|
||||
throw new customError("authorID does not exist", "apierror");
|
||||
}
|
||||
|
||||
if (exists == false) {
|
||||
// group does not exist
|
||||
callback(new customError("authorID does not exist", "apierror"));
|
||||
} else {
|
||||
// everything is fine, continue
|
||||
listSessionsWithDBKey("author2sessions:" + authorID, callback);
|
||||
}
|
||||
});
|
||||
});
|
||||
let sessions = await listSessionsWithDBKey("author2sessions:" + authorID);
|
||||
return sessions;
|
||||
}
|
||||
|
||||
// this function is basically the code listSessionsOfAuthor and listSessionsOfGroup has in common
|
||||
function listSessionsWithDBKey (dbkey, callback)
|
||||
// required to return null rather than an empty object if there are none
|
||||
async function listSessionsWithDBKey(dbkey, callback)
|
||||
{
|
||||
var sessions;
|
||||
// get the group2sessions entry
|
||||
let sessionObject = await db.get(dbkey);
|
||||
let sessions = sessionObject ? sessionObject.sessionIDs : null;
|
||||
|
||||
async.series([
|
||||
function(callback)
|
||||
{
|
||||
// get the group2sessions entry
|
||||
db.get(dbkey, function(err, sessionObject)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
sessions = sessionObject ? sessionObject.sessionIDs : null;
|
||||
callback();
|
||||
});
|
||||
},
|
||||
|
||||
function(callback)
|
||||
{
|
||||
// collect all sessionIDs in an arrary
|
||||
var sessionIDs = [];
|
||||
for (var i in sessions)
|
||||
{
|
||||
sessionIDs.push(i);
|
||||
// iterate through the sessions and get the sessioninfos
|
||||
for (let sessionID in sessions) {
|
||||
try {
|
||||
let sessionInfo = await exports.getSessionInfo(sessionID);
|
||||
sessions[sessionID] = sessionInfo;
|
||||
} catch (err) {
|
||||
if (err == "apierror: sessionID does not exist") {
|
||||
console.warn(`Found bad session ${sessionID} in ${dbkey}`);
|
||||
sessions[sessionID] = null;
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
|
||||
// iterate through the sessions and get the sessioninfos
|
||||
async.forEach(sessionIDs, function(sessionID, callback)
|
||||
{
|
||||
exports.getSessionInfo(sessionID, function(err, sessionInfo)
|
||||
{
|
||||
if (err == "apierror: sessionID does not exist") {
|
||||
console.warn(`Found bad session ${sessionID} in ${dbkey}`);
|
||||
} else if(ERR(err, callback)) {
|
||||
return;
|
||||
}
|
||||
|
||||
sessions[sessionID] = sessionInfo;
|
||||
callback();
|
||||
});
|
||||
}, callback);
|
||||
}
|
||||
], function(err)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
callback(null, sessions);
|
||||
});
|
||||
}
|
||||
|
||||
return sessions;
|
||||
}
|
||||
|
||||
// checks if a number is an int
|
||||
|
|
Loading…
Reference in New Issue