diff --git a/coffee/db_interface.coffee b/coffee/db_interface.coffee index f7b5774..fbed5e3 100644 --- a/coffee/db_interface.coffee +++ b/coffee/db_interface.coffee @@ -22,7 +22,7 @@ DB Interface 'use strict' ### Grab all required modules ### redis = require 'redis' -crypto = require 'crypto' +crypto = require 'crypto' # TODO change to Google's "crypto-js"" log = require './logging' crypto_key = null db = null @@ -129,7 +129,8 @@ via the provided function and returns the results to the callback(err, obj) func @param {function} fSingle a function to retrieve a single data element per set entry @param {function} cb the callback(err, obj) function that receives all the retrieved data or an error ### -getSetRecords = (set, funcSingle, cb) -> +getSetRecords = (set, fSingle, cb) -> + log.print 'DB', 'Fetching set records: ' + set db?.smembers set, (err, arrReply) -> if err err.addInfo = 'fetching ' + set @@ -146,12 +147,15 @@ getSetRecords = (set, funcSingle, cb) -> , 2000 fCallback = (prop) -> (err, data) -> + --semaphore if err err.addInfo = 'fetching single element: ' + prop log.error 'DB', err - else + else if not data + log.error 'DB', new Error 'Empty key in DB: ' + prop + else objReplies[prop] = data - if --semaphore == 0 + if semaphore == 0 cb null, objReplies fSingle reply, fCallback(reply) for reply in arrReply @@ -168,6 +172,7 @@ Store a string representation of an action module in the DB. ### # FIXME can the data be an object? exports.storeActionModule = (id, data) -> + log.print 'DB', 'storeActionModule: ' + id db?.sadd 'action-modules', id, replyHandler 'storing action module key ' + id db?.set 'action-module:' + id, data, replyHandler 'storing action module ' + id @@ -179,6 +184,7 @@ Query the DB for an action module and pass it to the callback(err, obj) function @param {function} cb ### exports.getActionModule = (id, cb) -> + log.print 'DB', 'getActionModule: ' + id db?.get 'action-module:' + id, cb ### @@ -199,6 +205,7 @@ Store a string representation of the authentication parameters for an action mod @param {String} data ### exports.storeActionAuth = (userId, moduleId, data) -> + log.print 'DB', 'storeActionAuth: ' + userId + ':' + moduleId db?.set 'action-auth:' + userId + ':' + moduleId, encrypt(data), replyHandler 'storing action auth ' + userId + ':' + moduleId @@ -212,6 +219,7 @@ and pass it to the callback(err, obj) function. @param {function} cb ### exports.getActionAuth = (userId, moduleId, cb) -> + log.print 'DB', 'getActionAuth: ' + userId + ':' + moduleId db?.get 'action-auth:' + userId + ':' + moduleId, (err, data) -> cb err, decrypt data @@ -228,6 +236,7 @@ Store a string representation of an event module in the DB. @param {String} data ### exports.storeEventModule = (id, data) -> + log.print 'DB', 'storeEventModule: ' + id db?.sadd 'event-modules', id, replyHandler 'storing event module key ' + id db?.set 'event-module:' + id, data, replyHandler 'storing event module ' + id @@ -239,6 +248,7 @@ Query the DB for an event module and pass it to the callback(err, obj) function. @param {function} cb ### exports.getEventModule = (id, cb) -> + log.print 'DB', 'getEventModule: ' + id db?.get 'event_module:' + id, cb ### @@ -258,6 +268,7 @@ Store a string representation of he authentication parameters for an event modul @param {String} data ### exports.storeEventAuth = (userId, moduleId, data) -> + log.print 'DB', 'storeEventAuth: ' + userId + ':' + moduleId db?.set 'event-auth:' + userId + ':' + moduleId, encrypt(data), replyHandler 'storing event auth ' + userId + ':' + moduleId @@ -269,6 +280,7 @@ Query the DB for an action module authentication token, associated with a user. @param {function} cb ### exports.getEventAuth = (userId, moduleId, cb) -> + log.print 'DB', 'getEventAuth: ' + userId + ':' + moduleId db?.get 'event-auth:' + userId + ':' + moduleId, (err, data) -> cb err, decrypt data @@ -285,6 +297,7 @@ Store a string representation of a rule in the DB. @param {String} data ### exports.storeRule = (id, data) -> + log.print 'DB', 'storeRule: ' + id db?.sadd 'rules', id, replyHandler 'storing rule key ' + id db?.set 'rule:' + id, data, replyHandler 'storing rule ' + id @@ -296,6 +309,7 @@ Query the DB for a rule and pass it to the callback(err, obj) function. @param {function} cb ### exports.getRule = (id, cb) -> + log.print 'DB', 'getRule: ' + id db?.get 'rule:' + id, cb ### @@ -305,6 +319,7 @@ Fetch all rules from the database and pass them to the callback function. @param {function} cb ### exports.getRules = (cb) -> + log.print 'DB', 'Fetching all Rules' getSetRecords 'rules', exports.getRule, cb ### @@ -314,6 +329,7 @@ Store a user object (needs to be a flat structure). @param {Object} objUser ### exports.storeUser = (objUser) -> + log.print 'DB', 'storeUser: ' + objUser.username if objUser and objUser.username and objUser.password db?.sadd 'users', objUser.username, replyHandler 'storing user key ' + objUser.username objUser.password = encrypt objUser.password @@ -329,6 +345,7 @@ Associate a role with a user. @param {String} role ### exports.storeUserRole = (username, role) -> + log.print 'DB', 'storeUserRole: ' + username + ':' + role db?.sadd 'user-roles:' + username, role, replyHandler 'adding role ' + role + ' to user ' + username db?.sadd 'role-users:' + role, username, replyHandler 'adding user ' + username + ' to role ' + role @@ -339,6 +356,7 @@ Fetch all roles of a user and pass them to the callback(err, obj) @param {String} username ### exports.getUserRoles = (username) -> + log.print 'DB', 'getUserRole: ' + username db?.get 'user-roles:' + username, cb ### @@ -348,6 +366,7 @@ Fetch all users of a role and pass them to the callback(err, obj) @param {String} role ### exports.getRoleUsers = (role) -> + log.print 'DB', 'getRoleUsers: ' + role db?.get 'role-users:' + role, cb ### @@ -360,18 +379,22 @@ Checks the credentials and on success returns the user object to the callback(er ### # TODO verify and test whole function exports.loginUser = (username, password, cb) -> + log.print 'DB', 'User "' + username + '" tries to log in' fCheck = (pw) -> (err, obj) -> if err - cb? err - else if obj and obj.password - if encrypt(obj.password) == pw - cb? null, obj - else cb? new Error 'Wrong credentials!' + cb err + else if obj and obj.password + if encrypt(pw) == obj.password + log.print 'DB', 'User "' + obj.username + '" logged in!' + cb null, obj + else + cb new Error 'Wrong credentials!' else - cb? new Error 'Empty arguments!' - db?.get 'user:' + username, fCheck password + cb new Error 'Empty arguments!' + db?.hgetall 'user:' + username, fCheck password +# TODO implement functions required for user sessions and the rule activation ### Shuts down the db link. diff --git a/js-coffee/db_interface.js b/js-coffee/db_interface.js index d25fcb0..77a9afc 100644 --- a/js-coffee/db_interface.js +++ b/js-coffee/db_interface.js @@ -173,7 +173,8 @@ DB Interface */ - getSetRecords = function(set, funcSingle, cb) { + getSetRecords = function(set, fSingle, cb) { + log.print('DB', 'Fetching set records: ' + set); return db != null ? db.smembers(set, function(err, arrReply) { var fCallback, objReplies, reply, semaphore, _i, _len, _results; if (err) { @@ -191,12 +192,15 @@ DB Interface }, 2000); fCallback = function(prop) { return function(err, data) { + --semaphore; if (err) { err.addInfo = 'fetching single element: ' + prop; return log.error('DB', err); + } else if (!data) { + return log.error('DB', new Error('Empty key in DB: ' + prop)); } else { objReplies[prop] = data; - if (--semaphore === 0) { + if (semaphore === 0) { return cb(null, objReplies); } } @@ -227,6 +231,7 @@ DB Interface exports.storeActionModule = function(id, data) { + log.print('DB', 'storeActionModule: ' + id); if (db != null) { db.sadd('action-modules', id, replyHandler('storing action module key ' + id)); } @@ -243,6 +248,7 @@ DB Interface exports.getActionModule = function(id, cb) { + log.print('DB', 'getActionModule: ' + id); return db != null ? db.get('action-module:' + id, cb) : void 0; }; @@ -269,6 +275,7 @@ DB Interface exports.storeActionAuth = function(userId, moduleId, data) { + log.print('DB', 'storeActionAuth: ' + userId + ':' + moduleId); return db != null ? db.set('action-auth:' + userId + ':' + moduleId, encrypt(data), replyHandler('storing action auth ' + userId + ':' + moduleId)) : void 0; }; @@ -284,6 +291,7 @@ DB Interface exports.getActionAuth = function(userId, moduleId, cb) { + log.print('DB', 'getActionAuth: ' + userId + ':' + moduleId); return db != null ? db.get('action-auth:' + userId + ':' + moduleId, function(err, data) { return cb(err, decrypt(data)); }) : void 0; @@ -304,6 +312,7 @@ DB Interface exports.storeEventModule = function(id, data) { + log.print('DB', 'storeEventModule: ' + id); if (db != null) { db.sadd('event-modules', id, replyHandler('storing event module key ' + id)); } @@ -320,6 +329,7 @@ DB Interface exports.getEventModule = function(id, cb) { + log.print('DB', 'getEventModule: ' + id); return db != null ? db.get('event_module:' + id, cb) : void 0; }; @@ -345,6 +355,7 @@ DB Interface exports.storeEventAuth = function(userId, moduleId, data) { + log.print('DB', 'storeEventAuth: ' + userId + ':' + moduleId); return db != null ? db.set('event-auth:' + userId + ':' + moduleId, encrypt(data), replyHandler('storing event auth ' + userId + ':' + moduleId)) : void 0; }; @@ -358,6 +369,7 @@ DB Interface exports.getEventAuth = function(userId, moduleId, cb) { + log.print('DB', 'getEventAuth: ' + userId + ':' + moduleId); return db != null ? db.get('event-auth:' + userId + ':' + moduleId, function(err, data) { return cb(err, decrypt(data)); }) : void 0; @@ -378,6 +390,7 @@ DB Interface exports.storeRule = function(id, data) { + log.print('DB', 'storeRule: ' + id); if (db != null) { db.sadd('rules', id, replyHandler('storing rule key ' + id)); } @@ -394,6 +407,7 @@ DB Interface exports.getRule = function(id, cb) { + log.print('DB', 'getRule: ' + id); return db != null ? db.get('rule:' + id, cb) : void 0; }; @@ -406,6 +420,7 @@ DB Interface exports.getRules = function(cb) { + log.print('DB', 'Fetching all Rules'); return getSetRecords('rules', exports.getRule, cb); }; @@ -418,6 +433,7 @@ DB Interface exports.storeUser = function(objUser) { + log.print('DB', 'storeUser: ' + objUser.username); if (objUser && objUser.username && objUser.password) { if (db != null) { db.sadd('users', objUser.username, replyHandler('storing user key ' + objUser.username)); @@ -439,6 +455,7 @@ DB Interface exports.storeUserRole = function(username, role) { + log.print('DB', 'storeUserRole: ' + username + ':' + role); if (db != null) { db.sadd('user-roles:' + username, role, replyHandler('adding role ' + role + ' to user ' + username)); } @@ -454,6 +471,7 @@ DB Interface exports.getUserRoles = function(username) { + log.print('DB', 'getUserRole: ' + username); return db != null ? db.get('user-roles:' + username, cb) : void 0; }; @@ -466,6 +484,7 @@ DB Interface exports.getRoleUsers = function(role) { + log.print('DB', 'getRoleUsers: ' + role); return db != null ? db.get('role-users:' + role, cb) : void 0; }; @@ -481,22 +500,24 @@ DB Interface exports.loginUser = function(username, password, cb) { var fCheck; + log.print('DB', 'User "' + username + '" tries to log in'); fCheck = function(pw) { return function(err, obj) { if (err) { - return typeof cb === "function" ? cb(err) : void 0; + return cb(err); } else if (obj && obj.password) { - if (encrypt(obj.password) === pw) { - return typeof cb === "function" ? cb(null, obj) : void 0; + if (encrypt(pw) === obj.password) { + log.print('DB', 'User "' + obj.username + '" logged in!'); + return cb(null, obj); } else { - return typeof cb === "function" ? cb(new Error('Wrong credentials!')) : void 0; + return cb(new Error('Wrong credentials!')); } } else { - return typeof cb === "function" ? cb(new Error('Empty arguments!')) : void 0; + return cb(new Error('Empty arguments!')); } }; }; - return db != null ? db.get('user:' + username, fCheck(password)) : void 0; + return db != null ? db.hgetall('user:' + username, fCheck(password)) : void 0; }; /* diff --git a/js-coffee/engine.js b/js-coffee/engine.js index 68664e0..d79cecc 100644 --- a/js-coffee/engine.js +++ b/js-coffee/engine.js @@ -63,7 +63,10 @@ exports.addDBLinkAndLoadActionsAndRules = function(db_link) { function loadRulesFromDB() { if(db) db.getRules(function(err, obj) { - for(var el in obj) exports.addRule(JSON.parse(obj[el])); + for(var el in obj){ + if(obj[el]) exports.addRule(JSON.parse(obj[el])); + } + }); } @@ -82,6 +85,8 @@ exports.loadActionModule = function(name, objModule) { */ exports.addRule = function(objRule) { //TODO validate rule + log.print('EN', 'Loading Rule'); + log.print('EN', objRule); log.print('EN', 'Loading Rule: ' + objRule.id); if(listRules[objRule.id]) log.print('EN', 'Replacing rule: ' + objRule.id); listRules[objRule.id] = objRule; diff --git a/js-coffee/logging.js b/js-coffee/logging.js index d4ee683..336d081 100644 --- a/js-coffee/logging.js +++ b/js-coffee/logging.js @@ -55,7 +55,10 @@ exports.print = function(module, msg) { */ function printError(module, err, isSevere) { var ts = (new Date()).toISOString() + ' | ', ai = ''; - if(!err) err = new Error('Unexpected error'); + if(!err) { + err = new Error('Unexpected error'); + isSevere = true; + } if(typeof err === 'string') err = new Error(err); // if(module) flush(true, ts + module + ' | ERROR AND BAD HANDLING: ' + err + '\n' + e.stack); // else flush(true, ts + '!N/A! | ERROR, BAD HANDLING AND NO MODULE NAME: ' + err + '\n' + e.stack); diff --git a/js-coffee/user_handler.js b/js-coffee/user_handler.js index 7511ed8..0eed5b8 100644 --- a/js-coffee/user_handler.js +++ b/js-coffee/user_handler.js @@ -9,8 +9,9 @@ exports = module.exports = function(args) { log(args); db(args); var users = JSON.parse(require('fs').readFileSync(path.resolve(__dirname, '..', 'config', 'users.json'))); - for(var name in users) { - db.storeUser(users[name]); + for(var i = 0; i < users.length; i++) { + log.print('UH', 'Found user ' + users[i].username + ' in user file, storing him in the DB'); + db.storeUser(users[i]); } return module.exports; @@ -42,13 +43,20 @@ exports.handleLogin = function(req, resp) { if(!req.session || !req.session.user) { var obj = qs.parse(body); db.loginUser(obj.username, obj.password, function(err, obj) { - if(!err) req.session.user = obj; - if(req.session.user) { - resp.write('Welcome ' + req.session.user.name + '!'); - } else { + if(err) { + log.error('UH', err); resp.writeHead(401, { "Content-Type": "text/plain" }); resp.write('Login failed!'); } + else { + req.session.user = obj; + if(req.session.user) { + resp.write('Welcome ' + req.session.user.name + '!'); + } else { + resp.writeHead(401, { "Content-Type": "text/plain" }); + resp.write('Login failed!'); + } + } resp.end(); }); } diff --git a/js/engine.js b/js/engine.js index 68664e0..79916a9 100644 --- a/js/engine.js +++ b/js/engine.js @@ -30,13 +30,14 @@ exports = module.exports = function(args) { * @param {String} crypto_key the key to be used for encryption on the db, max legnth 256 */ exports.addDBLinkAndLoadActionsAndRules = function(db_link) { + //TODO only load rules on beginning, if rules require certain actions, load them in order to allow fast firing + // if rules are set inactive, remove the action module from the memory db = db_link; if(ml && db) db.getActionModules(function(err, obj) { if(err) log.error('EN', 'retrieving Action Modules from DB!'); else { if(!obj) { log.print('EN', 'No Action Modules found in DB!'); - loadRulesFromDB(); } else { var m; for(var el in obj) { @@ -54,23 +55,22 @@ exports.addDBLinkAndLoadActionsAndRules = function(db_link) { log.error('EN', e); } } - loadRulesFromDB(); } } + if(db) db.getRules(function(err, obj) { + for(var el in obj) exports.addRule(JSON.parse(obj[el])); + }); }); else log.severe('EN', new Error('Module Loader or DB not defined!')); }; -function loadRulesFromDB() { - if(db) db.getRules(function(err, obj) { - for(var el in obj) exports.addRule(JSON.parse(obj[el])); - }); -} /** * Insert an action module into the list of available interfaces. * @param {Object} objModule the action module object */ +//TODO action modules should be loaded once a user activates a rule with the respective +// action, if the user deletes the rule it has to be garrbage collected from the engine's list exports.loadActionModule = function(name, objModule) { log.print('EN', 'Action module "' + name + '" loaded'); listActionModules[name] = objModule; @@ -82,6 +82,7 @@ exports.loadActionModule = function(name, objModule) { */ exports.addRule = function(objRule) { //TODO validate rule + log.print('EN', 'Loading Rule'); log.print('EN', 'Loading Rule: ' + objRule.id); if(listRules[objRule.id]) log.print('EN', 'Replacing rule: ' + objRule.id); listRules[objRule.id] = objRule; diff --git a/js/eventpoller.js b/js/eventpoller.js index 7198bc1..0be62b9 100644 --- a/js/eventpoller.js +++ b/js/eventpoller.js @@ -121,6 +121,7 @@ function checkRemotes() { * define and immediately call anonymous function with param prop. * This places the value of prop into the context of the callback * and thus doesn't change when the for loop keeps iterating over listPoll + * TODO add this example to the documentation and elaborate */ (function(p) { return function(err, obj) { diff --git a/js/logging.js b/js/logging.js index d4ee683..abed35d 100644 --- a/js/logging.js +++ b/js/logging.js @@ -55,18 +55,21 @@ exports.print = function(module, msg) { */ function printError(module, err, isSevere) { var ts = (new Date()).toISOString() + ' | ', ai = ''; - if(!err) err = new Error('Unexpected error'); + if(!err) { + err = new Error('Unexpected error'); + isSevere = true; + } if(typeof err === 'string') err = new Error(err); // if(module) flush(true, ts + module + ' | ERROR AND BAD HANDLING: ' + err + '\n' + e.stack); // else flush(true, ts + '!N/A! | ERROR, BAD HANDLING AND NO MODULE NAME: ' + err + '\n' + e.stack); // } else if(err) { - if(err.addInfo) ai = ' (' + err.addInfo + ')'; - if(!err.message) err.message = 'UNKNOWN REASON!\n' + err.stack; - if(module) { - var msg = ts + module + ' | ERROR'+ai+': ' + err.message; - if(isSevere) msg += '\n' + err.stack; - flush(true, msg); - } else flush(true, ts + '!N/A! | ERROR AND NO MODULE NAME'+ai+': ' + err.message + '\n' + err.stack); + if(err.addInfo) ai = ' (' + err.addInfo + ')'; + if(!err.message) err.message = 'UNKNOWN REASON!\n' + err.stack; + if(module) { + var msg = ts + module + ' | ERROR'+ai+': ' + err.message; + if(isSevere) msg += '\n' + err.stack; + flush(true, msg); + } else flush(true, ts + '!N/A! | ERROR AND NO MODULE NAME'+ai+': ' + err.message + '\n' + err.stack); // } else { // var e = new Error('Unexpected error'); // flush(true, e.message + ': \n' + e.stack); diff --git a/package.json b/package.json index 5c1a0d2..0c5cac3 100644 --- a/package.json +++ b/package.json @@ -21,8 +21,6 @@ "dependencies": { "glob" :"3.2.7", "docco": "0.6.2", - "groc": "0.6.1", - "diff": "1.0.5", "socket.io": "0.9.16", "contextify": "0.1.6" }