admin command newuser added

This commit is contained in:
Dominic Bosch 2014-04-21 14:42:26 +02:00
parent bc999b6012
commit d7c09e2e2e
16 changed files with 221 additions and 69 deletions

View file

@ -50,14 +50,14 @@ exports.addRuleListener = ( eh ) =>
eventEmitter.addListener 'rule', eh eventEmitter.addListener 'rule', eh
# Fetch all active rules per user # Fetch all active rules per user
db.getAllActivatedRuleIdsPerUser ( err, objUsers ) -> db.getAllActivatedRuleIdsPerUser ( err, objUsers ) =>
# Go through all rules of each user # Go through all rules of each user
fGoThroughUsers = ( user, rules ) -> fGoThroughUsers = ( user, rules ) =>
# Fetch the rules object for each rule in each user # Fetch the rules object for each rule in each user
fFetchRule = ( userName ) -> fFetchRule = ( userName ) =>
( rule ) -> ( rule ) =>
db.getRule rule, ( err, strRule ) => db.getRule rule, ( err, strRule ) =>
try try
oRule = JSON.parse strRule oRule = JSON.parse strRule

View file

@ -124,13 +124,14 @@ updateActionModules = ( updatedRuleId ) =>
fRequired = ( actionName ) -> fRequired = ( actionName ) ->
for action in oUser[updatedRuleId].rule.actions for action in oUser[updatedRuleId].rule.actions
# Since the event is in the format 'module -> function' we need to split the string # Since the event is in the format 'module -> function' we need to split the string
if (action.split ' -> ')[0] is actionName if (action.split ' -> ')[ 0 ] is actionName
return true return true
false false
# Go thorugh all loaded action modules and check whether the action is still required # Go thorugh all loaded action modules and check whether the action is still required
for action of oUser[updatedRuleId].rule.actions if oUser[updatedRuleId]
delete oUser[updatedRuleId].actions[action] if not fRequired action for action of oUser[updatedRuleId].rule.actions
delete oUser[updatedRuleId].actions[action] if not fRequired action
fRemoveNotRequired oUser for name, oUser of listUserRules fRemoveNotRequired oUser for name, oUser of listUserRules
@ -142,7 +143,7 @@ updateActionModules = ( updatedRuleId ) =>
# Load the action invoker module if it was part of the updated rule or if it's new # Load the action invoker module if it was part of the updated rule or if it's new
fAddIfNewOrNotExisting = ( actionName ) => fAddIfNewOrNotExisting = ( actionName ) =>
moduleName = (actionName.split ' -> ')[0] moduleName = (actionName.split ' -> ')[ 0 ]
if not oMyRule.actions[moduleName] or oMyRule.rule.id is updatedRuleId if not oMyRule.actions[moduleName] or oMyRule.rule.id is updatedRuleId
db.actionInvokers.getModule moduleName, ( err, obj ) => db.actionInvokers.getModule moduleName, ( err, obj ) =>
if obj if obj

View file

@ -624,9 +624,10 @@ exports.storeUser = ( objUser ) =>
if objUser and objUser.username and objUser.password if objUser and objUser.username and objUser.password
@db.sadd 'users', objUser.username, @db.sadd 'users', objUser.username,
replyHandler "sadd 'users' -> '#{ objUser.username }'" replyHandler "sadd 'users' -> '#{ objUser.username }'"
objUser.password = objUser.password
@db.hmset "user:#{ objUser.username }", objUser, @db.hmset "user:#{ objUser.username }", objUser,
replyHandler "hmset 'user:#{ objUser.username }' -> [objUser]" replyHandler "hmset 'user:#{ objUser.username }' -> [objUser]"
@db.hset "user:#{ objUser.username }", "roles", JSON.stringify( objUser.roles ),
replyHandler "hset 'user:#{ objUser.username }' field 'roles' -> [objUser]"
else else
@log.warn new Error 'DB | username or password was missing' @log.warn new Error 'DB | username or password was missing'
@ -649,7 +650,10 @@ Fetch a user by id and pass it to cb(err, obj).
### ###
exports.getUser = ( userId, cb ) => exports.getUser = ( userId, cb ) =>
@log.info "DB | getUser: '#{ userId }'" @log.info "DB | getUser: '#{ userId }'"
@db.hgetall "user:#{ userId }", cb @db.hgetall "user:#{ userId }", ( err, obj ) =>
try
obj.roles = JSON.parse obj.roles
cb err, obj
### ###
Deletes a user and all his associated linked and active rules. Deletes a user and all his associated linked and active rules.
@ -708,6 +712,7 @@ exports.loginUser = ( userId, password, cb ) =>
else if obj and obj.password else if obj and obj.password
if pw is obj.password if pw is obj.password
@log.info "DB | User '#{ obj.username }' logged in!" @log.info "DB | User '#{ obj.username }' logged in!"
obj.roles = JSON.parse obj.roles
cb null, obj cb null, obj
else else
cb (new Error 'Wrong credentials!'), null cb (new Error 'Wrong credentials!'), null

View file

@ -25,7 +25,9 @@ qs = require 'querystring'
# [crypto-js](https://github.com/evanvosberg/crypto-js) # [crypto-js](https://github.com/evanvosberg/crypto-js)
mustache = require 'mustache' mustache = require 'mustache'
crypto = require 'crypto-js' crypto = require 'crypto-js'
pathUsers = path.resolve __dirname, '..', 'config', 'users.json'
# Prepare the user command handlers which are invoked via HTTP requests. # Prepare the user command handlers which are invoked via HTTP requests.
dirHandlers = path.resolve __dirname, '..', 'webpages', 'handlers' dirHandlers = path.resolve __dirname, '..', 'webpages', 'handlers'
exports = module.exports = ( args ) => exports = module.exports = ( args ) =>
@ -42,10 +44,53 @@ exports = module.exports = ( args ) =>
message: 'Shutting down... BYE!' message: 'Shutting down... BYE!'
setTimeout args[ 'shutdown-function' ], 500 setTimeout args[ 'shutdown-function' ], 500
cb null, data cb null, data
newuser: ( obj, cb ) ->
data =
code: 200
message: 'User stored thank you!'
if obj.username and obj.password
if obj.roles
try
roles = JSON.parse obj.roles
catch err
@log 'RH | error parsing newuser roles: ' + err.message
roles = []
else
roles = []
oUser =
username: obj.username
password: obj.password
roles: roles
db.storeUser oUser
fPersistNewUser = ( username, password, roles ) ->
( err, data ) ->
users = JSON.parse data
users[ username ] =
password: password
roles: roles
fs.writeFile pathUsers, JSON.stringify( users, undefined, 2 ), 'utf8', ( err ) ->
if err
@log.error "RH | Unable to write new user file! "
@log.error err
# {
# "admin": {
# "password": "7407946a7a90b037ba5e825040f184a142161e4c61d81feb83ec8c7f011a99b0d77f39c9170c3231e1003c5cf859c69bd93043b095feff5cce6f6d45ec513764",
# "roles": ["admin"]
# }
# }
# {"admin":{"password":"7407946a7a90b037ba5e825040f184a142161e4c61d81feb83ec8c7f011a99b0d77f39c9170c3231e1003c5cf859c69bd93043b095feff5cce6f6d45ec513764","roles":["admin"]},"dominic":{"password":"2d51496fbe5b6d3e98e22d68140609eaedd64de457b2f75c346a4a98f87928eac11ea2be747709ae7a2f5b177af09a60a8dbf14bf703e0cb9b147fc0a3e3a064","roles":[]}}
fs.readFile pathUsers, 'utf8', fPersistNewUser obj.username, obj.password, roles
else
data.code = 401
data.message = 'Missing parameter for this command'
cb null, data
db args db args
# Load the standard users from the user config file # Load the standard users from the user config file
users = JSON.parse fs.readFileSync path.resolve __dirname, '..', 'config', 'users.json' users = JSON.parse fs.readFileSync pathUsers, 'utf8'
fStoreUser = ( username, oUser ) -> fStoreUser = ( username, oUser ) ->
oUser.username = username oUser.username = username
db.storeUser oUser db.storeUser oUser
@ -280,9 +325,9 @@ exports.handleAdmin = ( req, resp ) ->
if not req.session.user if not req.session.user
page = 'login' page = 'login'
#TODO isAdmin should come from the db role #TODO isAdmin should come from the db role
else if req.session.user.isAdmin isnt "true" else if req.session.user.roles.indexOf( "admin" ) is -1
page = 'login' page = 'login'
msg = 'You need to be admin!' msg = 'You need to be admin for this page!'
else else
page = 'admin' page = 'admin'
renderPage page, req, resp, msg renderPage page, req, resp, msg
@ -299,19 +344,26 @@ objects.*
### ###
exports.handleAdminCommand = ( req, resp ) => exports.handleAdminCommand = ( req, resp ) =>
if req.session and if req.session and
req.session.user and req.session.user and
req.session.user.isAdmin is "true" req.session.user.roles.indexOf( "admin" ) > -1
body = '' body = ''
req.on 'data', ( data ) -> req.on 'data', ( data ) ->
body += data body += data
req.on 'end', => req.on 'end', =>
obj = qs.parse body obj = qs.parse body
@log.info 'RH | Received admin request: ' + obj.command @log.info 'RH | Received admin request: ' + obj.command
if obj.command and @objAdminCmds[obj.command] arrCmd = obj.command.split( ' ' )
@objAdminCmds[obj.command] obj, ( err, obj ) -> if not arrCmd[ 0 ] or not @objAdminCmds[ arrCmd[ 0 ] ]
resp.send obj.code, obj
else
resp.send 404, 'Command unknown!' resp.send 404, 'Command unknown!'
else
arrParams = arrCmd.slice 1
oParams = {}
for keyVal in arrParams
arrKV = keyVal.split ":"
if arrKV.length is 2
oParams[ arrKV[ 0 ] ] = arrKV[ 1 ]
@objAdminCmds[ arrCmd[ 0 ] ] oParams, ( err, obj ) ->
resp.send obj.code, obj
else else
resp.send 401, 'You need to be logged in as admin!' resp.send 401, 'You need to be logged in as admin!'

View file

@ -1,10 +1,12 @@
{ {
"admin": { "admin": {
"password": "7407946a7a90b037ba5e825040f184a142161e4c61d81feb83ec8c7f011a99b0d77f39c9170c3231e1003c5cf859c69bd93043b095feff5cce6f6d45ec513764", "password": "7407946a7a90b037ba5e825040f184a142161e4c61d81feb83ec8c7f011a99b0d77f39c9170c3231e1003c5cf859c69bd93043b095feff5cce6f6d45ec513764",
"roles": [ "admin" ] "roles": [
"admin"
]
}, },
"dominic": { "dominic": {
"password": "2d51496fbe5b6d3e98e22d68140609eaedd64de457b2f75c346a4a98f87928eac11ea2be747709ae7a2f5b177af09a60a8dbf14bf703e0cb9b147fc0a3e3a064", "password": "2d51496fbe5b6d3e98e22d68140609eaedd64de457b2f75c346a4a98f87928eac11ea2be747709ae7a2f5b177af09a60a8dbf14bf703e0cb9b147fc0a3e3a064",
"roles": [ "admin" ] "roles": []
} }
} }

View file

@ -61,24 +61,22 @@ Components Manager
var fFetchRule, rule, _i, _len, _results; var fFetchRule, rule, _i, _len, _results;
fFetchRule = function(userName) { fFetchRule = function(userName) {
return function(rule) { return function(rule) {
return db.getRule(rule, (function(_this) { return db.getRule(rule, function(err, strRule) {
return function(err, strRule) { var oRule;
var oRule; try {
try { oRule = JSON.parse(strRule);
oRule = JSON.parse(strRule); db.resetLog(userName, oRule.id);
db.resetLog(userName, oRule.id); db.appendLog(userName, oRule.id, "INIT", "Rule '" + oRule.id + "' initialized. Interval set to " + oRule.event_interval + " minutes");
db.appendLog(userName, oRule.id, "INIT", "Rule '" + oRule.id + "' initialized. Interval set to " + oRule.event_interval + " minutes"); return eventEmitter.emit('rule', {
return eventEmitter.emit('rule', { event: 'init',
event: 'init', user: userName,
user: userName, rule: oRule
rule: oRule });
}); } catch (_error) {
} catch (_error) { err = _error;
err = _error; return _this.log.warn("CM | There's an invalid rule in the system: " + strRule);
return _this.log.warn("CM | There's an invalid rule in the system: " + strRule); }
} });
};
})(this));
}; };
}; };
_results = []; _results = [];

View file

@ -142,15 +142,17 @@ Engine
} }
return false; return false;
}; };
_results = []; if (oUser[updatedRuleId]) {
for (action in oUser[updatedRuleId].rule.actions) { _results = [];
if (!fRequired(action)) { for (action in oUser[updatedRuleId].rule.actions) {
_results.push(delete oUser[updatedRuleId].actions[action]); if (!fRequired(action)) {
} else { _results.push(delete oUser[updatedRuleId].actions[action]);
_results.push(void 0); } else {
_results.push(void 0);
}
} }
return _results;
} }
return _results;
}; };
for (name in listUserRules) { for (name in listUserRules) {
oUser = listUserRules[name]; oUser = listUserRules[name];

View file

@ -839,8 +839,8 @@ Persistence
_this.log.info("DB | storeUser: '" + objUser.username + "'"); _this.log.info("DB | storeUser: '" + objUser.username + "'");
if (objUser && objUser.username && objUser.password) { if (objUser && objUser.username && objUser.password) {
_this.db.sadd('users', objUser.username, replyHandler("sadd 'users' -> '" + objUser.username + "'")); _this.db.sadd('users', objUser.username, replyHandler("sadd 'users' -> '" + objUser.username + "'"));
objUser.password = objUser.password; _this.db.hmset("user:" + objUser.username, objUser, replyHandler("hmset 'user:" + objUser.username + "' -> [objUser]"));
return _this.db.hmset("user:" + objUser.username, objUser, replyHandler("hmset 'user:" + objUser.username + "' -> [objUser]")); return _this.db.hset("user:" + objUser.username, "roles", JSON.stringify(objUser.roles), replyHandler("hset 'user:" + objUser.username + "' field 'roles' -> [objUser]"));
} else { } else {
return _this.log.warn(new Error('DB | username or password was missing')); return _this.log.warn(new Error('DB | username or password was missing'));
} }
@ -874,7 +874,12 @@ Persistence
exports.getUser = (function(_this) { exports.getUser = (function(_this) {
return function(userId, cb) { return function(userId, cb) {
_this.log.info("DB | getUser: '" + userId + "'"); _this.log.info("DB | getUser: '" + userId + "'");
return _this.db.hgetall("user:" + userId, cb); return _this.db.hgetall("user:" + userId, function(err, obj) {
try {
obj.roles = JSON.parse(obj.roles);
} catch (_error) {}
return cb(err, obj);
});
}; };
})(this); })(this);
@ -957,6 +962,7 @@ Persistence
} else if (obj && obj.password) { } else if (obj && obj.password) {
if (pw === obj.password) { if (pw === obj.password) {
_this.log.info("DB | User '" + obj.username + "' logged in!"); _this.log.info("DB | User '" + obj.username + "' logged in!");
obj.roles = JSON.parse(obj.roles);
return cb(null, obj); return cb(null, obj);
} else { } else {
return cb(new Error('Wrong credentials!'), null); return cb(new Error('Wrong credentials!'), null);

View file

@ -11,7 +11,7 @@ Request Handler
*/ */
(function() { (function() {
var crypto, db, dirHandlers, exports, fs, getHandlerPath, getRemoteScripts, getScript, getTemplate, mustache, path, qs, renderPage; var crypto, db, dirHandlers, exports, fs, getHandlerPath, getRemoteScripts, getScript, getTemplate, mustache, path, pathUsers, qs, renderPage;
db = require('./persistence'); db = require('./persistence');
@ -25,6 +25,8 @@ Request Handler
crypto = require('crypto-js'); crypto = require('crypto-js');
pathUsers = path.resolve(__dirname, '..', 'config', 'users.json');
dirHandlers = path.resolve(__dirname, '..', 'webpages', 'handlers'); dirHandlers = path.resolve(__dirname, '..', 'webpages', 'handlers');
exports = module.exports = (function(_this) { exports = module.exports = (function(_this) {
@ -41,10 +43,57 @@ Request Handler
}; };
setTimeout(args['shutdown-function'], 500); setTimeout(args['shutdown-function'], 500);
return cb(null, data); return cb(null, data);
},
newuser: function(obj, cb) {
var data, err, fPersistNewUser, oUser, roles;
data = {
code: 200,
message: 'User stored thank you!'
};
if (obj.username && obj.password) {
if (obj.roles) {
try {
roles = JSON.parse(obj.roles);
} catch (_error) {
err = _error;
this.log('RH | error parsing newuser roles: ' + err.message);
roles = [];
}
} else {
roles = [];
}
oUser = {
username: obj.username,
password: obj.password,
roles: roles
};
db.storeUser(oUser);
fPersistNewUser = function(username, password, roles) {
return function(err, data) {
var users;
users = JSON.parse(data);
users[username] = {
password: password,
roles: roles
};
return fs.writeFile(pathUsers, JSON.stringify(users, void 0, 2), 'utf8', function(err) {
if (err) {
this.log.error("RH | Unable to write new user file! ");
return this.log.error(err);
}
});
};
};
fs.readFile(pathUsers, 'utf8', fPersistNewUser(obj.username, obj.password, roles));
} else {
data.code = 401;
data.message = 'Missing parameter for this command';
}
return cb(null, data);
} }
}; };
db(args); db(args);
users = JSON.parse(fs.readFileSync(path.resolve(__dirname, '..', 'config', 'users.json'))); users = JSON.parse(fs.readFileSync(pathUsers, 'utf8'));
fStoreUser = function(username, oUser) { fStoreUser = function(username, oUser) {
oUser.username = username; oUser.username = username;
return db.storeUser(oUser); return db.storeUser(oUser);
@ -329,9 +378,9 @@ Request Handler
var msg, page; var msg, page;
if (!req.session.user) { if (!req.session.user) {
page = 'login'; page = 'login';
} else if (req.session.user.isAdmin !== "true") { } else if (req.session.user.roles.indexOf("admin") === -1) {
page = 'login'; page = 'login';
msg = 'You need to be admin!'; msg = 'You need to be admin for this page!';
} else { } else {
page = 'admin'; page = 'admin';
} }
@ -353,21 +402,31 @@ Request Handler
exports.handleAdminCommand = (function(_this) { exports.handleAdminCommand = (function(_this) {
return function(req, resp) { return function(req, resp) {
var body; var body;
if (req.session && req.session.user && req.session.user.isAdmin === "true") { if (req.session && req.session.user && req.session.user.roles.indexOf("admin") > -1) {
body = ''; body = '';
req.on('data', function(data) { req.on('data', function(data) {
return body += data; return body += data;
}); });
return req.on('end', function() { return req.on('end', function() {
var obj; var arrCmd, arrKV, arrParams, keyVal, oParams, obj, _i, _len;
obj = qs.parse(body); obj = qs.parse(body);
_this.log.info('RH | Received admin request: ' + obj.command); _this.log.info('RH | Received admin request: ' + obj.command);
if (obj.command && _this.objAdminCmds[obj.command]) { arrCmd = obj.command.split(' ');
return _this.objAdminCmds[obj.command](obj, function(err, obj) { if (!arrCmd[0] || !_this.objAdminCmds[arrCmd[0]]) {
return resp.send(404, 'Command unknown!');
} else {
arrParams = arrCmd.slice(1);
oParams = {};
for (_i = 0, _len = arrParams.length; _i < _len; _i++) {
keyVal = arrParams[_i];
arrKV = keyVal.split(":");
if (arrKV.length === 2) {
oParams[arrKV[0]] = arrKV[1];
}
}
return _this.objAdminCmds[arrCmd[0]](oParams, function(err, obj) {
return resp.send(obj.code, obj); return resp.send(obj.code, obj);
}); });
} else {
return resp.send(404, 'Command unknown!');
} }
}); });
} else { } else {

View file

@ -111,17 +111,18 @@
"users": { "users": {
"userOne": { "userOne": {
"username": "tester-1", "username": "tester-1",
"password": "password-1" "password": "password-1",
"roles": []
}, },
"userTwo": { "userTwo": {
"username": "tester-2", "username": "tester-2",
"password": "password-2" "password": "password-2",
"roles": []
}, },
"userAdmin": { "userAdmin": {
"username": "tester-admin", "username": "tester-admin",
"password": "password-admin", "password": "password-admin",
"roles": [ "admin" ], "roles": [ "admin" ]
"isAdmin": true
} }
} }

View file

@ -2,6 +2,11 @@
fOnLoad = () -> fOnLoad = () ->
document.title = 'Administrate' document.title = 'Administrate'
$( '#pagetitle' ).text 'Hi {{{user.username}}}, issue your commands please:' $( '#pagetitle' ).text 'Hi {{{user.username}}}, issue your commands please:'
if not window.CryptoJS
$( '#info' ).attr 'class', 'error'
$( '#info' ).text 'CryptoJS library missing! Are you connected to the internet?'
$( '#but_submit' ).click () -> $( '#but_submit' ).click () ->
data = data =
command: $( '#inp_command' ).val() command: $( '#inp_command' ).val()
@ -19,4 +24,9 @@ fOnLoad = () ->
window.location.href = 'admin' window.location.href = 'admin'
setTimeout fDelayed, 500 setTimeout fDelayed, 500
$( '#inp_password' ).keyup () ->
hp = CryptoJS.SHA3 $( this ).val(),
outputLength: 512
$( '#display_hash' ).text hp.toString()
window.addEventListener 'load', fOnLoad, true window.addEventListener 'load', fOnLoad, true

View file

@ -514,7 +514,7 @@ fOnLoad = () ->
$( '#event_interval' ).val oRule.event_interval $( '#event_interval' ).val oRule.event_interval
# Conditions # Conditions
editor.setValue JSON.stringify oRule.conditions editor.setValue JSON.stringify oRule.conditions, undefined, 2
# Actions # Actions
for action in oRule.actions for action in oRule.actions

View file

@ -5,7 +5,11 @@
fOnLoad = function() { fOnLoad = function() {
document.title = 'Administrate'; document.title = 'Administrate';
$('#pagetitle').text('Hi {{{user.username}}}, issue your commands please:'); $('#pagetitle').text('Hi {{{user.username}}}, issue your commands please:');
return $('#but_submit').click(function() { if (!window.CryptoJS) {
$('#info').attr('class', 'error');
$('#info').text('CryptoJS library missing! Are you connected to the internet?');
}
$('#but_submit').click(function() {
var data; var data;
data = { data = {
command: $('#inp_command').val() command: $('#inp_command').val()
@ -28,6 +32,13 @@
return setTimeout(fDelayed, 500); return setTimeout(fDelayed, 500);
}); });
}); });
return $('#inp_password').keyup(function() {
var hp;
hp = CryptoJS.SHA3($(this).val(), {
outputLength: 512
});
return $('#display_hash').text(hp.toString());
});
}; };
window.addEventListener('load', fOnLoad, true); window.addEventListener('load', fOnLoad, true);

View file

@ -666,7 +666,7 @@
} }
$('#input_event').val(oRule.event); $('#input_event').val(oRule.event);
$('#event_interval').val(oRule.event_interval); $('#event_interval').val(oRule.event_interval);
editor.setValue(JSON.stringify(oRule.conditions)); editor.setValue(JSON.stringify(oRule.conditions, void 0, 2));
_ref = oRule.actions; _ref = oRule.actions;
_results = []; _results = [];
for (_j = 0, _len1 = _ref.length; _j < _len1; _j++) { for (_j = 0, _len1 = _ref.length; _j < _len1; _j++) {

View file

@ -0,0 +1 @@
<script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/sha3.js"></script>

View file

@ -1,2 +1,6 @@
<input type="text" id="inp_command" style="width:300px" /> <input type="text" id="inp_command" style="width:300px" />
<button type="button" id="but_submit">command</button> <button type="button" id="but_submit">command</button>
<br><br>
<h3>Get your password hashed:</h3>
<input type="password" id="inp_password" style="width:300px" />
<div id="display_hash" style="font-size:10px" />