initial rewrite

This commit is contained in:
booo 2012-02-09 02:09:17 +01:00
parent e6e81135a7
commit c19444f6c9
12 changed files with 777 additions and 697 deletions

View file

@ -19,163 +19,167 @@
*/
var ERR = require("async-stacktrace");
var db = require("./DB").db;
var async = require("async");
var randomString = require("../utils/randomstring");
var AuthorManager = function AuthorManager(db) {
this.db = db;
};
exports.AuthorManager = AuthorManager;
/**
* Checks if the author exists
*/
exports.doesAuthorExists = function (authorID, callback)
AuthorManager.prototype.doesAuthorExists = function (authorID, callback)
{
//check if the database entry of this author exists
db.get("globalAuthor:" + authorID, function (err, author)
this.db.get("globalAuthor:" + authorID, function (err, author)
{
if(ERR(err, callback)) return;
callback(null, author != null);
});
}
};
/**
* Returns the AuthorID for a token.
* @param {String} token The token
* @param {Function} callback callback (err, author)
* Returns the AuthorID for a token.
* @param {String} token The token
* @param {Function} callback callback (err, author)
*/
exports.getAuthor4Token = function (token, callback)
AuthorManager.prototype.getAuthor4Token = function (token, callback)
{
mapAuthorWithDBKey("token2author", token, function(err, author)
this.mapAuthorWithDBKey("token2author", token, function(err, author)
{
if(ERR(err, callback)) return;
//return only the sub value authorID
callback(null, author ? author.authorID : author);
});
}
};
/**
* Returns the AuthorID for a mapper.
* Returns the AuthorID for a mapper.
* @param {String} token The mapper
* @param {Function} callback callback (err, author)
* @param {Function} callback callback (err, author)
*/
exports.createAuthorIfNotExistsFor = function (authorMapper, name, callback)
AuthorManager.prototype.createAuthorIfNotExistsFor = function (authorMapper, name, callback)
{
mapAuthorWithDBKey("mapper2author", authorMapper, function(err, author)
var that = this;
this.mapAuthorWithDBKey("mapper2author", authorMapper, function(err, author)
{
if(ERR(err, callback)) return;
//set the name of this author
if(name)
exports.setAuthorName(author.authorID, name);
that.setAuthorName(author.authorID, name);
//return the authorID
callback(null, author);
});
}
};
/**
* Returns the AuthorID for a mapper. We can map using a mapperkey,
* so far this is token2author and mapper2author
* @param {String} mapperkey The database key name for this mapper
* @param {String} mapperkey The database key name for this mapper
* @param {String} mapper The mapper
* @param {Function} callback callback (err, author)
* @param {Function} callback callback (err, author)
*/
function mapAuthorWithDBKey (mapperkey, mapper, callback)
{
AuthorManager.prototype.mapAuthorWithDBKey = function mapAuthorWithDBKey (mapperkey, mapper, callback) {
var that = this;
//try to map to an author
db.get(mapperkey + ":" + mapper, function (err, author)
this.db.get(mapperkey + ":" + mapper, function (err, author)
{
if(ERR(err, callback)) return;
//there is no author with this mapper, so create one
if(author == null)
{
exports.createAuthor(null, function(err, author)
{
that.createAuthor(null, function(err, author) {
if(ERR(err, callback)) return;
//create the token2author relation
db.set(mapperkey + ":" + mapper, author.authorID);
that.db.set(mapperkey + ":" + mapper, author.authorID);
//return the author
callback(null, author);
});
}
//there is a author with this mapper
else
{
else {
//update the timestamp of this author
db.setSub("globalAuthor:" + author, ["timestamp"], new Date().getTime());
that.db.setSub("globalAuthor:" + author, ["timestamp"], new Date().getTime());
//return the author
callback(null, {authorID: author});
}
});
}
};
/**
* Internal function that creates the database entry for an author
* @param {String} name The name of the author
* Internal function that creates the database entry for an author
* @param {String} name The name of the author
*/
exports.createAuthor = function(name, callback)
AuthorManager.prototype.createAuthor = function(name, callback)
{
//create the new author name
var author = "a." + randomString(16);
//create the globalAuthors db entry
var authorObj = {"colorId" : Math.floor(Math.random()*32), "name": name, "timestamp": new Date().getTime()};
//set the global author db entry
db.set("globalAuthor:" + author, authorObj);
this.db.set("globalAuthor:" + author, authorObj);
callback(null, {authorID: author});
}
};
/**
* Returns the Author Obj of the author
* @param {String} author The id of the author
* @param {Function} callback callback(err, authorObj)
*/
exports.getAuthor = function (author, callback)
AuthorManager.prototype.getAuthor = function (author, callback)
{
db.get("globalAuthor:" + author, callback);
}
this.db.get("globalAuthor:" + author, callback);
};
/**
* Returns the color Id of the author
* @param {String} author The id of the author
* @param {Function} callback callback(err, colorId)
*/
exports.getAuthorColorId = function (author, callback)
AuthorManager.prototype.getAuthorColorId = function (author, callback)
{
db.getSub("globalAuthor:" + author, ["colorId"], callback);
}
this.db.getSub("globalAuthor:" + author, ["colorId"], callback);
};
/**
* Sets the color Id of the author
* @param {String} author The id of the author
* @param {Function} callback (optional)
*/
exports.setAuthorColorId = function (author, colorId, callback)
AuthorManager.prototype.setAuthorColorId = function (author, colorId, callback)
{
db.setSub("globalAuthor:" + author, ["colorId"], colorId, callback);
}
this.db.setSub("globalAuthor:" + author, ["colorId"], colorId, callback);
};
/**
* Returns the name of the author
* @param {String} author The id of the author
* @param {Function} callback callback(err, name)
*/
exports.getAuthorName = function (author, callback)
AuthorManager.prototype.getAuthorName = function (author, callback)
{
db.getSub("globalAuthor:" + author, ["name"], callback);
}
this.db.getSub("globalAuthor:" + author, ["name"], callback);
};
/**
* Sets the name of the author
* @param {String} author The id of the author
* @param {Function} callback (optional)
*/
exports.setAuthorName = function (author, name, callback)
AuthorManager.prototype.setAuthorName = function (author, name, callback)
{
db.setSub("globalAuthor:" + author, ["name"], name, callback);
}
this.db.setSub("globalAuthor:" + author, ["name"], name, callback);
};

View file

@ -1,5 +1,5 @@
/**
* The DB Module provides a database initalized with the settings
* The DB Module provides a database initalized with the settings
* provided by the settings module
*/
@ -20,38 +20,25 @@
*/
var ueberDB = require("ueberDB");
var settings = require("../utils/Settings");
var log4js = require('log4js');
//set database settings
var db = new ueberDB.database(settings.dbType, settings.dbSettings, null, log4js.getLogger("ueberDB"));
/**
* The UeberDB Object that provides the database functions
*/
exports.db = null;
/**
* Initalizes the database with the settings provided by the settings module
* @param {Function} callback
* @param {Function} callback
*/
exports.init = function(callback)
{
//initalize the database async
db.init(function(err)
{
//there was an error while initializing the database, output it and stop
if(err)
{
console.error("ERROR: Problem while initalizing the database");
console.error(err.stack ? err.stack : err);
process.exit(1);
}
//everything ok
else
{
exports.db = db;
callback(null);
}
});
}
exports.init = function init(settings, callback) {
//set database settings
console.log(settings);
var db = new ueberDB.database(settings.dbType, settings.dbSettings, null, log4js.getLogger("ueberDB"));
//initalize the database async
db.init(function(error){
//there was an error while initializing the database, output it and stop
if(error) {
callback(error, null);
}
else {
callback(null, db);
}
});
};

View file

@ -17,28 +17,35 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
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 padManager = require("./PadManager");
var sessionManager = require("./SessionManager");
exports.deleteGroup = function(groupID, callback)
var GroupManager = function GroupManager(db, padManager, SessionManager) {
this.db = db;
this.padManager = padManager;
this.SessionManager = SessionManager;
};
exports.GroupManager = GroupManager;
GroupManager.prototype.deleteGroup = function(groupID, callback)
{
var group;
var that = this;
async.series([
//ensure group exists
//ensure group exists
function (callback)
{
//try to get the group entry
db.get("group:" + groupID, function (err, _group)
that.db.get("group:" + groupID, function (err, _group)
{
if(ERR(err, callback)) return;
//group does not exist
if(_group == null)
{
@ -61,14 +68,14 @@ exports.deleteGroup = function(groupID, callback)
{
padIDs.push(i);
}
//loop trough all pads and delete them
//loop trough all pads and delete them
async.forEach(padIDs, function(padID, callback)
{
padManager.getPad(padID, function(err, pad)
that.padManager.getPad(padID, function(err, pad)
{
if(ERR(err, callback)) return;
pad.remove(callback);
});
}, callback);
@ -77,21 +84,21 @@ exports.deleteGroup = function(groupID, callback)
function(callback)
{
//try to get the group entry
db.get("group2sessions:" + groupID, function (err, group2sessions)
that.db.get("group2sessions:" + groupID, function (err, group2sessions)
{
if(ERR(err, callback)) return;
//skip if there is no group2sessions entry
if(group2sessions == null) {callback(); return}
//collect all sessions in an array, that allows us to use async.forEach
var sessions = [];
for(var i in group2sessions.sessionsIDs)
{
sessions.push(i);
}
//loop trough all sessions and delete them
//loop trough all sessions and delete them
async.forEach(sessions, function(session, callback)
{
sessionManager.deleteSession(session, callback);
@ -101,8 +108,8 @@ exports.deleteGroup = function(groupID, callback)
//remove group and group2sessions entry
function(callback)
{
db.remove("group2sessions:" + groupID);
db.remove("group:" + groupID);
that.db.remove("group2sessions:" + groupID);
that.db.remove("group:" + groupID);
callback();
}
], function(err)
@ -110,52 +117,53 @@ exports.deleteGroup = function(groupID, callback)
if(ERR(err, callback)) return;
callback();
});
}
exports.doesGroupExist = function(groupID, callback)
};
GroupManager.prototype.doesGroupExist = function(groupID, callback)
{
//try to get the group entry
db.get("group:" + groupID, function (err, group)
this.db.get("group:" + groupID, function (err, group)
{
if(ERR(err, callback)) return;
callback(null, group != null);
});
}
};
exports.createGroup = function(callback)
GroupManager.prototype.createGroup = function(callback)
{
//search for non existing groupID
var groupID = "g." + randomString(16);
//create the group
db.set("group:" + groupID, {pads: {}});
callback(null, {groupID: groupID});
}
exports.createGroupIfNotExistsFor = function(groupMapper, callback)
//create the group
this.db.set("group:" + groupID, {pads: {}});
callback(null, {groupID: groupID});
};
GroupManager.prototype.createGroupIfNotExistsFor = function(groupMapper, callback)
{
var that = this;
//ensure mapper is optional
if(typeof groupMapper != "string")
{
callback(new customError("groupMapper is no string","apierror"));
return;
}
//try to get a group for this mapper
db.get("mapper2group:"+groupMapper, function(err, groupID)
this.db.get("mapper2group:"+groupMapper, function(err, groupID)
{
if(ERR(err, callback)) return;
//there is no group for this mapper, let's create a group
if(groupID == null)
{
exports.createGroup(function(err, responseObj)
that.createGroup(function(err, responseObj)
{
if(ERR(err, callback)) return;
//create the mapper entry for this group
db.set("mapper2group:"+groupMapper, responseObj.groupID);
that.db.set("mapper2group:"+groupMapper, responseObj.groupID);
callback(null, responseObj);
});
}
@ -166,21 +174,22 @@ exports.createGroupIfNotExistsFor = function(groupMapper, callback)
callback(null, {groupID: groupID});
}
});
}
};
exports.createGroupPad = function(groupID, padName, text, callback)
GroupManager.prototype.createGroupPad = function(groupID, padName, text, callback)
{
var that = this;
//create the padID
var padID = groupID + "$" + padName;
async.series([
//ensure group exists
//ensure group exists
function (callback)
{
exports.doesGroupExist(groupID, function(err, exists)
that.doesGroupExist(groupID, function(err, exists)
{
if(ERR(err, callback)) return;
//group does not exist
if(exists == false)
{
@ -196,12 +205,12 @@ exports.createGroupPad = function(groupID, padName, text, callback)
//ensure pad does not exists
function (callback)
{
padManager.doesPadExists(padID, function(err, exists)
that.padManager.doesPadExists(padID, function(err, exists)
{
if(ERR(err, callback)) return;
//pad exists already
if(exists == true)
if(exists)
{
callback(new customError("padName does already exist","apierror"));
}
@ -215,7 +224,7 @@ exports.createGroupPad = function(groupID, padName, text, callback)
//create the pad
function (callback)
{
padManager.getPad(padID, text, function(err)
that.padManager.getPad(padID, text, function(err)
{
if(ERR(err, callback)) return;
callback();
@ -224,7 +233,7 @@ exports.createGroupPad = function(groupID, padName, text, callback)
//create an entry in the group for this pad
function (callback)
{
db.setSub("group:" + groupID, ["pads", padID], 1);
that.db.setSub("group:" + groupID, ["pads", padID], 1);
callback();
}
], function(err)
@ -232,27 +241,28 @@ exports.createGroupPad = function(groupID, padName, text, callback)
if(ERR(err, callback)) return;
callback(null, {padID: padID});
});
}
};
exports.listPads = function(groupID, callback)
GroupManager.prototype.listPads = function(groupID, callback)
{
exports.doesGroupExist(groupID, function(err, exists)
var that = this;
this.doesGroupExist(groupID, function(err, exists)
{
if(ERR(err, callback)) return;
//group does not exist
if(exists == false)
if(!exists)
{
callback(new customError("groupID does not exist","apierror"));
}
//group exists, let's get the pads
else
{
db.getSub("group:" + groupID, ["pads"], function(err, pads)
that.db.getSub("group:" + groupID, ["pads"], function(err, pads)
{
if(ERR(err, callback)) return;
callback(null, {padIDs: pads});
});
}
});
}
};

View file

@ -1,17 +1,11 @@
/**
* The pad object, defined with joose
* The pad object
*/
var ERR = require("async-stacktrace");
var Changeset = require("../utils/Changeset");
var AttributePoolFactory = require("../utils/AttributePoolFactory");
var db = require("./DB").db;
var async = require("async");
var settings = require('../utils/Settings');
var authorManager = require("./AuthorManager");
var padManager = require("./PadManager");
var padMessageHandler = require("../handler/PadMessageHandler");
var readOnlyManager = require("./ReadOnlyManager");
var crypto = require("crypto");
/**
@ -73,8 +67,8 @@ Pad.prototype.appendRevision = function appendRevision(aChangeset, author) {
newRevData.meta.atext = this.atext;
}
db.set("pad:"+this.id+":revs:"+newRev, newRevData);
db.set("pad:"+this.id, {atext: this.atext,
this.db.set("pad:"+this.id+":revs:"+newRev, newRevData);
this.db.set("pad:"+this.id, {atext: this.atext,
pool: this.pool.toJsonable(),
head: this.head,
chatHead: this.chatHead,
@ -83,15 +77,15 @@ Pad.prototype.appendRevision = function appendRevision(aChangeset, author) {
};
Pad.prototype.getRevisionChangeset = function getRevisionChangeset(revNum, callback) {
db.getSub("pad:"+this.id+":revs:"+revNum, ["changeset"], callback);
this.db.getSub("pad:"+this.id+":revs:"+revNum, ["changeset"], callback);
};
Pad.prototype.getRevisionAuthor = function getRevisionAuthor(revNum, callback) {
db.getSub("pad:"+this.id+":revs:"+revNum, ["meta", "author"], callback);
this.db.getSub("pad:"+this.id+":revs:"+revNum, ["meta", "author"], callback);
};
Pad.prototype.getRevisionDate = function getRevisionDate(revNum, callback) {
db.getSub("pad:"+this.id+":revs:"+revNum, ["meta", "timestamp"], callback);
this.db.getSub("pad:"+this.id+":revs:"+revNum, ["meta", "timestamp"], callback);
};
Pad.prototype.getAllAuthors = function getAllAuthors() {
@ -109,7 +103,7 @@ Pad.prototype.getAllAuthors = function getAllAuthors() {
};
Pad.prototype.getInternalRevisionAText = function getInternalRevisionAText(targetRev, callback) {
var _this = this;
var that = this;
var keyRev = this.getKeyRevisionNumber(targetRev);
var atext;
@ -132,7 +126,7 @@ Pad.prototype.getInternalRevisionAText = function getInternalRevisionAText(targe
//get the atext of the key revision
function (callback)
{
db.getSub("pad:"+_this.id+":revs:"+keyRev, ["meta", "atext"], function(err, _atext)
that.db.getSub("pad:"+that.id+":revs:"+keyRev, ["meta", "atext"], function(err, _atext)
{
if(ERR(err, callback)) return;
atext = Changeset.cloneAText(_atext);
@ -144,7 +138,7 @@ Pad.prototype.getInternalRevisionAText = function getInternalRevisionAText(targe
{
async.forEach(neededChangesets, function(item, callback)
{
_this.getRevisionChangeset(item, function(err, changeset)
that.getRevisionChangeset(item, function(err, changeset)
{
if(ERR(err, callback)) return;
changesets[item] = changeset;
@ -157,7 +151,7 @@ Pad.prototype.getInternalRevisionAText = function getInternalRevisionAText(targe
//apply all changesets to the key changeset
function(callback)
{
var apool = _this.apool();
var apool = that.apool();
var curRev = keyRev;
while (curRev < targetRev)
@ -200,20 +194,20 @@ Pad.prototype.setText = function setText(newText) {
Pad.prototype.appendChatMessage = function appendChatMessage(text, userId, time) {
this.chatHead++;
//save the chat entry in the database
db.set("pad:"+this.id+":chat:"+this.chatHead, {"text": text, "userId": userId, "time": time});
this.db.set("pad:"+this.id+":chat:"+this.chatHead, {"text": text, "userId": userId, "time": time});
//save the new chat head
db.setSub("pad:"+this.id, ["chatHead"], this.chatHead);
this.db.setSub("pad:"+this.id, ["chatHead"], this.chatHead);
};
Pad.prototype.getChatMessage = function getChatMessage(entryNum, callback) {
var _this = this;
var that = this;
var entry;
async.series([
//get the chat entry
function(callback)
{
db.get("pad:"+_this.id+":chat:"+entryNum, function(err, _entry)
that.db.get("pad:"+that.id+":chat:"+entryNum, function(err, _entry)
{
if(ERR(err, callback)) return;
entry = _entry;
@ -231,7 +225,7 @@ Pad.prototype.getChatMessage = function getChatMessage(entryNum, callback) {
}
//get the authorName
authorManager.getAuthorName(entry.userId, function(err, authorName)
that.authorManager.getAuthorName(entry.userId, function(err, authorName)
{
if(ERR(err, callback)) return;
entry.userName = authorName;
@ -253,7 +247,7 @@ Pad.prototype.getLastChatMessages = function getLastChatMessages(count, callback
return;
}
var _this = this;
var that = this;
//works only if we decrement the amount, for some reason
count--;
@ -279,7 +273,7 @@ Pad.prototype.getLastChatMessages = function getLastChatMessages(count, callback
var entries = [];
async.forEach(neededEntries, function(entryObject, callback)
{
_this.getChatMessage(entryObject.entryNum, function(err, entry)
that.getChatMessage(entryObject.entryNum, function(err, entry)
{
if(ERR(err, callback)) return;
entries[entryObject.order] = entry;
@ -298,7 +292,7 @@ Pad.prototype.getLastChatMessages = function getLastChatMessages(count, callback
if(entries[i]!=null)
cleanedEntries.push(entries[i]);
else
console.warn("WARNING: Found broken chat entry in pad " + _this.id);
console.warn("WARNING: Found broken chat entry in pad " + that.id);
}
callback(null, cleanedEntries);
@ -306,50 +300,45 @@ Pad.prototype.getLastChatMessages = function getLastChatMessages(count, callback
};
Pad.prototype.init = function init(text, callback) {
var _this = this;
var that = this;
//replace text with default text if text isn't set
if(text == null)
{
text = settings.defaultPadText;
}
//try to load the pad
db.get("pad:"+this.id, function(err, value)
this.db.get("pad:"+this.id, function(err, value)
{
if(ERR(err, callback)) return;
//if this pad exists, load it
if(value != null)
{
_this.head = value.head;
_this.atext = value.atext;
_this.pool = _this.pool.fromJsonable(value.pool);
that.head = value.head;
that.atext = value.atext;
that.pool = that.pool.fromJsonable(value.pool);
//ensure we have a local chatHead variable
if(value.chatHead != null)
_this.chatHead = value.chatHead;
that.chatHead = value.chatHead;
else
_this.chatHead = -1;
that.chatHead = -1;
//ensure we have a local publicStatus variable
if(value.publicStatus != null)
_this.publicStatus = value.publicStatus;
that.publicStatus = value.publicStatus;
else
_this.publicStatus = false;
that.publicStatus = false;
//ensure we have a local passwordHash variable
if(value.passwordHash != null)
_this.passwordHash = value.passwordHash;
that.passwordHash = value.passwordHash;
else
_this.passwordHash = null;
that.passwordHash = null;
}
//this pad doesn't exist, so create it
else
{
var firstChangeset = Changeset.makeSplice("\n", 0, 0, exports.cleanText(text));
_this.appendRevision(firstChangeset, '');
that.appendRevision(firstChangeset, '');
}
callback(null);
@ -358,10 +347,11 @@ Pad.prototype.init = function init(text, callback) {
Pad.prototype.remove = function remove(callback) {
var padID = this.id;
var _this = this;
var that = this;
//kick everyone from this pad
padMessageHandler.kickSessionsFromPad(padID);
//FIXME do this in the api or somewhere else
//padMessageHandler.kickSessionsFromPad(padID);
async.series([
//delete all relations
@ -376,7 +366,7 @@ Pad.prototype.remove = function remove(callback) {
{
var groupID = padID.substring(0,padID.indexOf("$"));
db.get("group:" + groupID, function (err, group)
that.db.get("group:" + groupID, function (err, group)
{
if(ERR(err, callback)) return;
@ -384,7 +374,7 @@ Pad.prototype.remove = function remove(callback) {
delete group.pads[padID];
//set the new value
db.set("group:" + groupID, group);
that.db.set("group:" + groupID, group);
callback();
});
@ -398,12 +388,12 @@ Pad.prototype.remove = function remove(callback) {
//remove the readonly entries
function(callback)
{
readOnlyManager.getReadOnlyId(padID, function(err, readonlyID)
that.readOnlyManager.getReadOnlyId(padID, function(err, readonlyID)
{
if(ERR(err, callback)) return;
db.remove("pad2readonly:" + padID);
db.remove("readonly2pad:" + readonlyID);
that.db.remove("pad2readonly:" + padID);
that.db.remove("readonly2pad:" + readonlyID);
callback();
});
@ -411,11 +401,11 @@ Pad.prototype.remove = function remove(callback) {
//delete all chat messages
function(callback)
{
var chatHead = _this.chatHead;
var chatHead = that.chatHead;
for(var i=0;i<=chatHead;i++)
{
db.remove("pad:"+padID+":chat:"+i);
that.db.remove("pad:"+padID+":chat:"+i);
}
callback();
@ -423,11 +413,11 @@ Pad.prototype.remove = function remove(callback) {
//delete all revisions
function(callback)
{
var revHead = _this.head;
var revHead = that.head;
for(var i=0;i<=revHead;i++)
{
db.remove("pad:"+padID+":revs:"+i);
that.db.remove("pad:"+padID+":revs:"+i);
}
callback();
@ -437,8 +427,8 @@ Pad.prototype.remove = function remove(callback) {
//delete the pad entry and delete pad from padManager
function(callback)
{
db.remove("pad:"+padID);
padManager.unloadPad(padID);
that.db.remove("pad:"+padID);
that.padManager.unloadPad(padID);
callback();
}
], function(err)
@ -450,12 +440,12 @@ Pad.prototype.remove = function remove(callback) {
//set in db
Pad.prototype.setPublicStatus = function setPublicStatus(publicStatus) {
this.publicStatus = publicStatus;
db.setSub("pad:"+this.id, ["publicStatus"], this.publicStatus);
this.db.setSub("pad:"+this.id, ["publicStatus"], this.publicStatus);
};
Pad.prototype.setPassword = function setPassword(password) {
this.passwordHash = password == null ? null : hash(password, generateSalt());
db.setSub("pad:"+this.id, ["passwordHash"], this.passwordHash);
this.db.setSub("pad:"+this.id, ["passwordHash"], this.passwordHash);
};
Pad.prototype.isCorrectPassword = function isCorrectPassword(password) {

View file

@ -21,9 +21,8 @@
var ERR = require("async-stacktrace");
var customError = require("../utils/customError");
var Pad = require("../db/Pad").Pad;
var db = require("./DB").db;
/**
/**
* An Object containing all known Pads. Provides "get" and "set" functions,
* which should be used instead of indexing with brackets. These prepend a
* colon to the key, to avoid conflicting with built-in Object methods or with
@ -32,12 +31,23 @@ var db = require("./DB").db;
* If this is needed in other places, it would be wise to make this a prototype
* that's defined somewhere more sensible.
*/
var globalPads = {
get: function (name) { return this[':'+name]; },
set: function (name, value) { this[':'+name] = value; },
remove: function (name) { delete this[':'+name]; }
var PadManager = function PadManager(settings, db, authorManager, readOnlyManager) {
this.settings = settings;
this.db = db;
this.authorManager = authorManager;
this.readOnlyManager = readOnlyManager;
this.globalPads = {
get: function (name) { return this[':'+name]; },
set: function (name, value) { this[':'+name] = value; },
remove: function (name) { delete this[':'+name]; }
};
};
exports.PadManager = PadManager;
/**
* An array of padId transformations. These represent changes in pad name policy over
* time, and allow us to "play back" these changes so legacy padIds can be found.
@ -49,24 +59,27 @@ var padIdTransforms = [
/**
* Returns a Pad Object with the callback
* @param id A String with the id of the pad
* @param {Function} callback
* @param {Function} callback
*/
exports.getPad = function(id, text, callback)
{
PadManager.prototype.getPad = function getPad(id, text, callback)
{
var that = this;
//TODO remove api specific shit
//check if this is a valid padId
if(!exports.isValidPadId(id))
if(!this.isValidPadId(id))
{
callback(new customError(id + " is not a valid padId","apierror"));
return;
}
//make text an optional parameter
if(typeof text == "function")
{
callback = text;
text = null;
}
//check if this is a valid text
if(text != null)
{
@ -76,7 +89,7 @@ exports.getPad = function(id, text, callback)
callback(new customError("text is not a string","apierror"));
return;
}
//check if text is less than 100k chars
if(text.length > 100000)
{
@ -84,42 +97,50 @@ exports.getPad = function(id, text, callback)
return;
}
}
var pad = globalPads.get(id);
var pad = this.globalPads.get(id);
//return pad if its already loaded
if(pad != null)
{
if(pad != null) {
callback(null, pad);
}
//try to load pad
else
{
else {
pad = new Pad(id);
//add some references
//TODO is this realy nice?
pad.padManager = this;
pad.db = this.db;
pad.readOnlyManager = this.readOnlyManager;
pad.authorManager = this.authorManager;
//initalize the pad
pad.init(text, function(err)
{
if(!text) {
text = this.settings.defaultPadText;
}
pad.init(text, function(err) {
if(ERR(err, callback)) return;
globalPads.set(id, pad);
that.globalPads.set(id, pad);
callback(null, pad);
});
}
}
};
//checks if a pad exists
exports.doesPadExists = function(padId, callback)
PadManager.prototype.doesPadExists = function doesPadExists(padId, callback)
{
db.get("pad:"+padId, function(err, value)
this.db.get("pad:"+padId, function(err, value)
{
if(ERR(err, callback)) return;
callback(null, value != null);
callback(null, value != null);
});
}
};
//returns a sanitized padId, respecting legacy pad id formats
exports.sanitizePadId = function(padId, callback) {
PadManager.prototype.sanitizePadId = function sanitizePadId(padId, callback) {
var that = this;
var transform_index = arguments[2] || 0;
//we're out of possible transformations, so just return it
if(transform_index >= padIdTransforms.length)
@ -129,7 +150,7 @@ exports.sanitizePadId = function(padId, callback) {
//check if padId exists
else
{
exports.doesPadExists(padId, function(junk, exists)
this.doesPadExists(padId, function(junk, exists)
{
if(exists)
{
@ -145,20 +166,18 @@ exports.sanitizePadId = function(padId, callback) {
transform_index += 1;
}
//check the next transform
exports.sanitizePadId(transformedPadId, callback, transform_index);
that.sanitizePadId(transformedPadId, callback, transform_index);
}
});
}
}
};
exports.isValidPadId = function(padId)
{
return /^(g.[a-zA-Z0-9]{16}\$)?[^$]{1,50}$/.test(padId);
}
PadManager.prototype.isValidPadId = function(padId) {
return (/^(g.[a-zA-Z0-9]{16}\$)?[^$]{1,50}$/).test(padId);
};
//removes a pad from the array
exports.unloadPad = function(padId)
{
if(globalPads.get(padId))
globalPads.remove(padId);
}
Pad.prototype.unloadPad = function unloadPad(padId) {
if(this.globalPads.get(padId))
this.globalPads.remove(padId);
};

View file

@ -19,24 +19,31 @@
*/
var ERR = require("async-stacktrace");
var db = require("./DB").db;
var async = require("async");
var randomString = require("../utils/randomstring");
var ReadOnlyManager = function ReadOnlyManager(db) {
this.db = db;
};
exports.ReadOnlyManager = ReadOnlyManager;
/**
* returns a read only id for a pad
* @param {String} padId the id of the pad
*/
exports.getReadOnlyId = function (padId, callback)
{
ReadOnlyManager.prototype.getReadOnlyId = function getReadOnlyId(padId, callback) {
var that = this;
var readOnlyId;
async.waterfall([
//check if there is a pad2readonly entry
function(callback)
{
db.get("pad2readonly:" + padId, callback);
that.db.get("pad2readonly:" + padId, callback);
},
function(dbReadOnlyId, callback)
{
@ -44,16 +51,16 @@ exports.getReadOnlyId = function (padId, callback)
if(dbReadOnlyId == null)
{
readOnlyId = "r." + randomString(16);
db.set("pad2readonly:" + padId, readOnlyId);
db.set("readonly2pad:" + readOnlyId, padId);
that.db.set("pad2readonly:" + padId, readOnlyId);
that.db.set("readonly2pad:" + readOnlyId, padId);
}
//there is a readOnly Entry in the database, let's take this one
else
{
readOnlyId = dbReadOnlyId;
}
callback();
}
], function(err)
@ -61,14 +68,13 @@ exports.getReadOnlyId = function (padId, callback)
if(ERR(err, callback)) return;
//return the results
callback(null, readOnlyId);
})
}
});
};
/**
* returns a the padId for a read only id
* @param {String} readOnlyId read only id
*/
exports.getPadId = function(readOnlyId, callback)
{
db.get("readonly2pad:" + readOnlyId, callback);
}
ReadOnlyManager.prototype.getPadId = function(readOnlyId, callback) {
this.db.get("readonly2pad:" + readOnlyId, callback);
};

View file

@ -19,15 +19,20 @@
*/
var ERR = require("async-stacktrace");
var db = require("./DB").db;
var async = require("async");
var authorManager = require("./AuthorManager");
var padManager = require("./PadManager");
var sessionManager = require("./SessionManager");
var settings = require("../utils/Settings")
var randomString = require("../utils/randomstring");
var SecurityManager = function SecurityManager(settings, db, authorManager, padManager, sessionManager) {
this.db = db;
this.settings = settings;
this.authorManager = authorManager;
this.padManager = padManager;
this.sessionManager = sessionManager;
};
exports.SecurityManager = SecurityManager;
/**
* This function controlls the access to a pad, it checks if the user can access a pad.
* @param padID the pad the user wants to access
@ -36,12 +41,13 @@ var randomString = require("../utils/randomstring");
* @param password the password the user has given to access this pad, can be null
* @param callback will be called with (err, {accessStatus: grant|deny|wrongPassword|needPassword, authorID: a.xxxxxx})
*/
exports.checkAccess = function (padID, sessionID, token, password, callback)
SecurityManager.prototype.checkAccess = function checkAccess(padID, sessionID, token, password, callback)
{
var that = this;
var statusObject;
// a valid session is required (api-only mode)
if(settings.requireSession)
if(this.settings.requireSession)
{
// no sessionID, access is denied
if(!sessionID)
@ -57,17 +63,17 @@ exports.checkAccess = function (padID, sessionID, token, password, callback)
if(padID.indexOf("$") == -1)
{
//get author for this token
authorManager.getAuthor4Token(token, function(err, author)
this.authorManager.getAuthor4Token(token, function(err, author)
{
if(ERR(err, callback)) return;
// assume user has access
statusObject = {accessStatus: "grant", authorID: author};
// user can't create pads
if(settings.editOnly)
if(that.settings.editOnly)
{
// check if pad exists
padManager.doesPadExists(padID, function(err, exists)
that.padManager.doesPadExists(padID, function(err, exists)
{
if(ERR(err, callback)) return;
@ -107,7 +113,7 @@ exports.checkAccess = function (padID, sessionID, token, password, callback)
//does pad exists
function(callback)
{
padManager.doesPadExists(padID, function(err, exists)
that.padManager.doesPadExists(padID, function(err, exists)
{
if(ERR(err, callback)) return;
padExists = exists;
@ -117,7 +123,7 @@ exports.checkAccess = function (padID, sessionID, token, password, callback)
//get informations about this session
function(callback)
{
sessionManager.getSessionInfo(sessionID, function(err, sessionInfo)
that.sessionManager.getSessionInfo(sessionID, function(err, sessionInfo)
{
//skip session validation if the session doesn't exists
if(err && err.message == "sessionID does not exist")
@ -145,7 +151,7 @@ exports.checkAccess = function (padID, sessionID, token, password, callback)
function(callback)
{
//get author for this token
authorManager.getAuthor4Token(token, function(err, author)
that.authorManager.getAuthor4Token(token, function(err, author)
{
if(ERR(err, callback)) return;
tokenAuthor = author;
@ -164,7 +170,7 @@ exports.checkAccess = function (padID, sessionID, token, password, callback)
return;
}
padManager.getPad(padID, function(err, pad)
that.padManager.getPad(padID, function(err, pad)
{
if(ERR(err, callback)) return;
@ -223,7 +229,7 @@ exports.checkAccess = function (padID, sessionID, token, password, callback)
//--> grant access
statusObject = {accessStatus: "grant", authorID: sessionAuthor};
//--> deny access if user isn't allowed to create the pad
if(settings.editOnly) statusObject.accessStatus = "deny";
if(that.settings.editOnly) statusObject.accessStatus = "deny";
}
// there is no valid session avaiable AND pad exists
else if(!validSession && padExists)
@ -277,4 +283,4 @@ exports.checkAccess = function (padID, sessionID, token, password, callback)
if(ERR(err, callback)) return;
callback(null, statusObject);
});
}
};

View file

@ -17,40 +17,47 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
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 groupMangager = require("./GroupManager");
var authorMangager = require("./AuthorManager");
exports.doesSessionExist = function(sessionID, callback)
var SessionManager = function SessionManager(db, groupManager, authorManager) {
this.db = db;
this.groupManager = groupManager;
this.authorManager = authorManager;
};
exports.SessionManager = SessionManager;
SessionManager.prototype.doesSessionExist = function(sessionID, callback)
{
//check if the database entry of this session exists
db.get("session:" + sessionID, function (err, session)
this.db.get("session:" + sessionID, function (err, session)
{
if(ERR(err, callback)) return;
callback(null, session != null);
});
}
};
/**
* Creates a new session between an author and a group
*/
exports.createSession = function(groupID, authorID, validUntil, callback)
SessionManager.prototype.createSession = function(groupID, authorID, validUntil, callback)
{
var sessionID;
var that = this;
async.series([
//check if group exists
function(callback)
{
groupMangager.doesGroupExist(groupID, function(err, exists)
that.groupMangager.doesGroupExist(groupID, function(err, exists)
{
if(ERR(err, callback)) return;
//group does not exist
if(exists == false)
{
@ -66,10 +73,10 @@ exports.createSession = function(groupID, authorID, validUntil, callback)
//check if author exists
function(callback)
{
authorMangager.doesAuthorExists(authorID, function(err, exists)
that.authorMangager.doesAuthorExists(authorID, function(err, exists)
{
if(ERR(err, callback)) return;
//author does not exist
if(exists == false)
{
@ -99,56 +106,56 @@ exports.createSession = function(groupID, authorID, validUntil, callback)
return;
}
}
//ensure this is not a negativ number
if(validUntil < 0)
{
callback(new customError("validUntil is a negativ number","apierror"));
return;
}
//ensure this is not a float value
if(!is_int(validUntil))
{
callback(new customError("validUntil is a float value","apierror"));
return;
}
//check if validUntil is in the future
if(Math.floor(new Date().getTime()/1000) > validUntil)
{
callback(new customError("validUntil is in the past","apierror"));
return;
}
//generate sessionID
sessionID = "s." + randomString(16);
//set the session into the database
db.set("session:" + sessionID, {"groupID": groupID, "authorID": authorID, "validUntil": validUntil});
that.db.set("session:" + sessionID, {"groupID": groupID, "authorID": authorID, "validUntil": validUntil});
callback();
},
//set the group2sessions entry
function(callback)
{
//get the entry
db.get("group2sessions:" + groupID, function(err, group2sessions)
that.db.get("group2sessions:" + groupID, function(err, group2sessions)
{
if(ERR(err, callback)) return;
//the entry doesn't exist so far, let's create it
if(group2sessions == null)
{
group2sessions = {sessionIDs : {}};
}
//add the entry for this session
group2sessions.sessionIDs[sessionID] = 1;
//save the new element back
db.set("group2sessions:" + groupID, group2sessions);
that.db.set("group2sessions:" + groupID, group2sessions);
callback();
});
},
@ -156,45 +163,45 @@ exports.createSession = function(groupID, authorID, validUntil, callback)
function(callback)
{
//get the entry
db.get("author2sessions:" + authorID, function(err, author2sessions)
that.db.get("author2sessions:" + authorID, function(err, author2sessions)
{
if(ERR(err, callback)) return;
//the entry doesn't exist so far, let's create it
if(author2sessions == null)
{
author2sessions = {sessionIDs : {}};
}
//add the entry for this session
author2sessions.sessionIDs[sessionID] = 1;
//save the new element back
db.set("author2sessions:" + authorID, author2sessions);
that.db.set("author2sessions:" + authorID, author2sessions);
callback();
});
}
], function(err)
{
if(ERR(err, callback)) return;
//return error and sessionID
callback(null, {sessionID: sessionID});
})
}
exports.getSessionInfo = function(sessionID, callback)
SessionManager.prototype.getSessionInfo = function(sessionID, callback)
{
//check if the database entry of this session exists
db.get("session:" + sessionID, function (err, session)
this.db.get("session:" + sessionID, function (err, session)
{
if(ERR(err, callback)) return;
//session does not exists
if(session == null)
{
callback(new customError("sessionID does not exist","apierror"))
callback(new customError("sessionID does not exist","apierror"));
}
//everything is fine, return the sessioninfos
else
@ -202,7 +209,7 @@ exports.getSessionInfo = function(sessionID, callback)
callback(null, session);
}
});
}
};
/**
* Deletes a session
@ -211,15 +218,16 @@ exports.deleteSession = function(sessionID, callback)
{
var authorID, groupID;
var group2sessions, author2sessions;
var that = this;
async.series([
function(callback)
{
//get the session entry
db.get("session:" + sessionID, function (err, session)
that.db.get("session:" + sessionID, function (err, session)
{
if(ERR(err, callback)) return;
//session does not exists
if(session == null)
{
@ -230,7 +238,7 @@ exports.deleteSession = function(sessionID, callback)
{
authorID = session.authorID;
groupID = session.groupID;
callback();
}
});
@ -238,7 +246,7 @@ exports.deleteSession = function(sessionID, callback)
//get the group2sessions entry
function(callback)
{
db.get("group2sessions:" + groupID, function (err, _group2sessions)
that.db.get("group2sessions:" + groupID, function (err, _group2sessions)
{
if(ERR(err, callback)) return;
group2sessions = _group2sessions;
@ -248,7 +256,7 @@ exports.deleteSession = function(sessionID, callback)
//get the author2sessions entry
function(callback)
{
db.get("author2sessions:" + authorID, function (err, _author2sessions)
that.db.get("author2sessions:" + authorID, function (err, _author2sessions)
{
if(ERR(err, callback)) return;
author2sessions = _author2sessions;
@ -259,16 +267,16 @@ exports.deleteSession = function(sessionID, callback)
function(callback)
{
//remove the session
db.remove("session:" + sessionID);
that.db.remove("session:" + sessionID);
//remove session from group2sessions
delete group2sessions.sessionIDs[sessionID];
db.set("group2sessions:" + groupID, group2sessions);
that.db.set("group2sessions:" + groupID, group2sessions);
//remove session from author2sessions
delete author2sessions.sessionIDs[sessionID];
db.set("author2sessions:" + authorID, author2sessions);
that.db.set("author2sessions:" + authorID, author2sessions);
callback();
}
], function(err)
@ -276,14 +284,15 @@ exports.deleteSession = function(sessionID, callback)
if(ERR(err, callback)) return;
callback();
})
}
};
exports.listSessionsOfGroup = function(groupID, callback)
SessionManager.prototype.listSessionsOfGroup = function(groupID, callback)
{
groupMangager.doesGroupExist(groupID, function(err, exists)
var that = this;
this.groupMangager.doesGroupExist(groupID, function(err, exists)
{
if(ERR(err, callback)) return;
//group does not exist
if(exists == false)
{
@ -292,17 +301,18 @@ exports.listSessionsOfGroup = function(groupID, callback)
//everything is fine, continue
else
{
listSessionsWithDBKey("group2sessions:" + groupID, callback);
that.listSessionsWithDBKey("group2sessions:" + groupID, callback);
}
});
}
};
exports.listSessionsOfAuthor = function(authorID, callback)
{
authorMangager.doesAuthorExists(authorID, function(err, exists)
SessionManager.prototype.listSessionsOfAuthor = function(authorID, callback)
{
var that = this;
this.authorMangager.doesAuthorExists(authorID, function(err, exists)
{
if(ERR(err, callback)) return;
//group does not exist
if(exists == false)
{
@ -311,21 +321,21 @@ exports.listSessionsOfAuthor = function(authorID, callback)
//everything is fine, continue
else
{
listSessionsWithDBKey("author2sessions:" + authorID, callback);
that.listSessionsWithDBKey("author2sessions:" + authorID, callback);
}
});
}
};
//this function is basicly the code listSessionsOfAuthor and listSessionsOfGroup has in common
function listSessionsWithDBKey (dbkey, callback)
SessionManager.prototype.listSessionsWithDBKey = function listSessionsWithDBKey (dbkey, callback)
{
var sessions;
var that = this;
async.series([
function(callback)
{
//get the group2sessions entry
db.get(dbkey, function(err, sessionObject)
that.db.get(dbkey, function(err, sessionObject)
{
if(ERR(err, callback)) return;
sessions = sessionObject ? sessionObject.sessionIDs : null;
@ -333,18 +343,18 @@ function listSessionsWithDBKey (dbkey, callback)
});
},
function(callback)
{
{
//collect all sessionIDs in an arrary
var sessionIDs = [];
for (var i in sessions)
{
sessionIDs.push(i);
}
//foreach trough the sessions and get the sessioninfos
async.forEach(sessionIDs, function(sessionID, callback)
{
exports.getSessionInfo(sessionID, function(err, sessionInfo)
that.getSessionInfo(sessionID, function(err, sessionInfo)
{
if(ERR(err, callback)) return;
sessions[sessionID] = sessionInfo;
@ -360,7 +370,6 @@ function listSessionsWithDBKey (dbkey, callback)
}
//checks if a number is an int
function is_int(value)
{
return (parseFloat(value) == parseInt(value)) && !isNaN(value)
function is_int(value) {
return (parseFloat(value) == parseInt(value, 10)) && !isNaN(value);
}