diff --git a/coffee/components-manager.coffee b/coffee/components-manager.coffee index 03113db..c7185d9 100644 --- a/coffee/components-manager.coffee +++ b/coffee/components-manager.coffee @@ -14,6 +14,8 @@ Components Manager db = require './persistence' # - [Dynamic Modules](dynamic-modules.html) dynmod = require './dynamic-modules' +# - [Encryption](encryption.html) +encryption = require './encryption' # - Node.js Modules: [fs](http://nodejs.org/api/fs.html), # [path](http://nodejs.org/api/path.html) and @@ -159,40 +161,109 @@ getModuleParams = ( user, oPayload, dbMod, callback ) -> answ.message = oPayload callback answ +getModuleUserParams = ( user, oPayload, dbMod, callback ) -> + answ = hasRequiredParams [ 'id' ], oPayload + if answ.code isnt 200 + callback answ + else + dbMod.getUserParams oPayload.id, user.username, ( err, str ) -> + oParams = JSON.parse str + for name, oParam of oParams + if not oParam.shielded + oParam.value = encryption.decrypt oParam.value + answ.message = JSON.stringify oParams + callback answ + +getModuleUserArguments = ( user, oPayload, dbMod, callback ) -> + answ = hasRequiredParams [ 'ruleId' ,'moduleId' ], oPayload + if answ.code isnt 200 + callback answ + else + dbMod.getAllModuleUserArguments user.username, oPayload.ruleId, oPayload.moduleId, ( err, oPayload ) -> + answ.message = oPayload + callback answ forgeModule = ( user, oPayload, dbMod, callback ) => answ = hasRequiredParams [ 'id', 'params', 'lang', 'data' ], oPayload if answ.code isnt 200 callback answ else - i = 0 - dbMod.getModule oPayload.id, ( err, mod ) => - if mod - answ.code = 409 - answ.message = 'Module name already existing: ' + oPayload.id - callback answ - else - src = oPayload.data - dynmod.compileString src, user.username, 'dummyRule', oPayload.id, oPayload.lang, null, ( cm ) => - answ = cm.answ - if answ.code is 200 - funcs = [] - funcs.push name for name, id of cm.module - @log.info "CM | Storing new module with functions #{ funcs.join( ', ' ) }" - answ.message = - " Module #{ oPayload.id } successfully stored! Found following function(s): #{ funcs }" - oPayload.functions = JSON.stringify funcs - oPayload.functionArgs = JSON.stringify cm.funcParams - dbMod.storeModule user.username, oPayload - if oPayload.public is 'true' - dbMod.publish oPayload.id + if oPayload.overwrite + storeModule user, oPayload, dbMod, callback + else + dbMod.getModule oPayload.id, ( err, mod ) => + if mod + answ.code = 409 + answ.message = 'Module name already existing: ' + oPayload.id callback answ + else + storeModule user, oPayload, dbMod, callback + +storeModule = ( user, oPayload, dbMod, callback ) => + src = oPayload.data + dynmod.compileString src, user.username, 'dummyRule', oPayload.id, oPayload.lang, null, ( cm ) => + answ = cm.answ + if answ.code is 200 + funcs = [] + funcs.push name for name, id of cm.module + @log.info "CM | Storing new module with functions #{ funcs.join( ', ' ) }" + answ.message = + " Module #{ oPayload.id } successfully stored! Found following function(s): #{ funcs }" + oPayload.functions = JSON.stringify funcs + oPayload.functionArgs = JSON.stringify cm.funcParams + dbMod.storeModule user.username, oPayload + if oPayload.public is 'true' + dbMod.publish oPayload.id + callback answ + +storeRule = ( user, oPayload, callback ) => + # This is how a rule is stored in the database + rule = + id: oPayload.id + event: oPayload.event + event_interval: oPayload.event_interval + conditions: oPayload.conditions + actions: oPayload.actions + strRule = JSON.stringify rule + # store the rule + db.storeRule rule.id, strRule + # link the rule to the user + db.linkRule rule.id, user.username + # activate the rule + db.activateRule rule.id, user.username + # if event module parameters were send, store them + if oPayload.event_params + epModId = rule.event.split( ' -> ' )[ 0 ] + db.eventPollers.storeUserParams epModId, user.username, JSON.stringify oPayload.event_params + + # if action module params were send, store them + oParams = oPayload.action_params + for id, params of oParams + db.actionInvokers.storeUserParams id, user.username, JSON.stringify params + oParams = oPayload.action_functions + # if action function arguments were send, store them + for id, params of oParams + arr = id.split ' -> ' + db.actionInvokers.storeUserArguments user.username, rule.id, arr[ 0 ], arr[ 1 ], JSON.stringify params + + # Initialize the rule log + db.resetLog user.username, rule.id + db.appendLog user.username, rule.id, "INIT", "Rule '#{ rule.id }' initialized" + + # Inform everbody about the new rule + eventEmitter.emit 'rule', + event: 'new' + user: user.username + rule: rule + callback + code: 200 + message: "Rule '#{ rule.id }' stored and activated!" commandFunctions = get_public_key: ( user, oPayload, callback ) -> callback code: 200 - message: dynmod.getPublicKey() + message: encryption.getPublicKey() # EVENT POLLERS # ------------- @@ -208,6 +279,12 @@ commandFunctions = get_event_poller_params: ( user, oPayload, callback ) -> getModuleParams user, oPayload, db.eventPollers, callback + get_event_poller_user_params: ( user, oPayload, callback ) -> + getModuleUserParams user, oPayload, db.eventPollers, callback + + get_event_poller_user_arguments: ( user, oPayload, callback ) -> + getModuleUserArguments user, oPayload, db.eventPollers, callback + forge_event_poller: ( user, oPayload, callback ) -> forgeModule user, oPayload, db.eventPollers, callback @@ -239,7 +316,13 @@ commandFunctions = get_action_invoker_params: ( user, oPayload, callback ) -> getModuleParams user, oPayload, db.actionInvokers, callback - get_action_invoker_function_params: ( user, oPayload, callback ) -> + get_action_invoker_user_params: ( user, oPayload, callback ) -> + getModuleUserParams user, oPayload, db.actionInvokers, callback + + get_action_invoker_user_arguments: ( user, oPayload, callback ) -> + getModuleUserArguments user, oPayload, db.actionInvokers, callback + + get_action_invoker_function_arguments: ( user, oPayload, callback ) -> answ = hasRequiredParams [ 'id' ], oPayload if answ.code isnt 200 callback answ @@ -270,6 +353,16 @@ commandFunctions = code: 200 message: obj + get_rule: ( user, oPayload, callback ) -> + answ = hasRequiredParams [ 'id' ], oPayload + if answ.code isnt 200 + callback answ + else + db.getRule oPayload.id, ( err, obj ) -> + callback + code: 200 + message: obj + get_rule_log: ( user, oPayload, callback ) -> answ = hasRequiredParams [ 'id' ], oPayload if answ.code isnt 200 @@ -291,54 +384,16 @@ commandFunctions = if answ.code isnt 200 callback answ else - db.getRule oPayload.id, ( err, oExisting ) -> - if oExisting isnt null - answ = - code: 409 - message: 'Rule name already existing!' - else - # This is how a rule is stored in the database - rule = - id: oPayload.id - event: oPayload.event - event_interval: oPayload.event_interval - conditions: oPayload.conditions - actions: oPayload.actions - strRule = JSON.stringify rule - # store the rule - db.storeRule rule.id, strRule - # link the rule to the user - db.linkRule rule.id, user.username - # activate the rule - db.activateRule rule.id, user.username - # if event module parameters were send, store them - if oPayload.event_params - epModId = rule.event.split( ' -> ' )[0] - db.eventPollers.storeUserParams epModId, user.username, oPayload.event_params - - # if action module params were send, store them - oParams = oPayload.action_params - for id, params of oParams - db.actionInvokers.storeUserParams id, user.username, JSON.stringify params - oParams = oPayload.action_functions - # if action function arguments were send, store them - for id, params of oParams - arr = id.split ' -> ' - db.actionInvokers.storeUserArguments user.username, rule.id, arr[ 0 ], arr[ 1 ], JSON.stringify params - - # Initialize the rule log - db.resetLog user.username, rule.id - db.appendLog user.username, rule.id, "INIT", "Rule '#{ rule.id }' initialized" - - # Inform everbody about the new rule - eventEmitter.emit 'rule', - event: 'new' - user: user.username - rule: rule - answ = - code: 200 - message: "Rule '#{ rule.id }' stored and activated!" - callback answ + if oPayload.overwrite + storeRule user, oPayload, callback + else + db.getRule oPayload.id, ( err, mod ) => + if mod + answ.code = 409 + answ.message = 'Rule name already existing: ' + oPayload.id + callback answ + else + storeRule user, oPayload, callback delete_rule: ( user, oPayload, callback ) -> answ = hasRequiredParams [ 'id' ], oPayload diff --git a/coffee/dynamic-modules.coffee b/coffee/dynamic-modules.coffee index 1ebd2b2..23fbce3 100644 --- a/coffee/dynamic-modules.coffee +++ b/coffee/dynamic-modules.coffee @@ -10,6 +10,8 @@ Dynamic Modules # - [Persistence](persistence.html) db = require './persistence' +# - [Encryption](encryption.html) +encryption = require './encryption' # - Node.js Modules: [vm](http://nodejs.org/api/vm.html) and # [events](http://nodejs.org/api/events.html) @@ -18,11 +20,9 @@ needle = require 'needle' request = require 'request' # - External Modules: [coffee-script](http://coffeescript.org/), -# [cryptico](https://github.com/wwwtyro/cryptico), # [crypto-js](https://www.npmjs.org/package/crypto-js) and # [import-io](https://www.npmjs.org/package/import-io) cs = require 'coffee-script' -cryptico = require 'my-cryptico' cryptoJS = require 'crypto-js' importio = require( 'import-io' ).client @@ -37,21 +37,9 @@ Initializes the dynamic module handler. ### exports = module.exports = ( args ) => @log = args.logger - # FIXME this can't come through the arguments - if not @strPublicKey and args[ 'keygen' ] - db args - passPhrase = args[ 'keygen' ] - numBits = 1024 - @oPrivateRSAkey = cryptico.generateRSAKey passPhrase, numBits - @strPublicKey = cryptico.publicKeyString @oPrivateRSAkey - @log.info "DM | Public Key generated: #{ @strPublicKey }" - + db args module.exports - -exports.getPublicKey = () => - @strPublicKey - logFunction = ( uId, rId, mId ) -> ( msg ) -> db.appendLog uId, rId, mId, msg @@ -61,7 +49,7 @@ getFunctionParamNames = ( fName, func, oFuncs ) -> fnStr = func.toString().replace regexpComments, '' result = fnStr.slice( fnStr.indexOf( '(' ) + 1, fnStr.indexOf( ')' ) ).match /([^\s,]+)/g if not result - result = [] + result = [] oFuncs[fName] = result ### @@ -93,13 +81,14 @@ exports.compileString = ( src, userId, ruleId, modId, lang, dbMod, cb ) => if dbMod dbMod.getUserParams modId, userId, ( err, obj ) => try - oDecrypted = cryptico.decrypt obj, @oPrivateRSAkey - obj = JSON.parse oDecrypted.plaintext + oParams = {} + for name, oParam of JSON.parse obj + oParams[ name ] = encryption.decrypt oParam.value @log.info "DM | Loaded user defined params for #{ userId }, #{ ruleId }, #{ modId }" catch err @log.warn "DM | Error during parsing of user defined params for #{ userId }, #{ ruleId }, #{ modId }" @log.warn err - fTryToLoadModule userId, ruleId, modId, src, dbMod, obj, cb + fTryToLoadModule userId, ruleId, modId, src, dbMod, oParams, cb else fTryToLoadModule userId, ruleId, modId, src, dbMod, null, cb @@ -156,8 +145,7 @@ fTryToLoadModule = ( userId, ruleId, modId, src, dbMod, params, cb ) => dbMod.getUserArguments userId, ruleId, modId, func, ( err, obj ) => if obj try - oDecrypted = cryptico.decrypt obj, @oPrivateRSAkey - oFuncArgs[ func ] = JSON.parse oDecrypted.plaintext + oFuncArgs[ func ] = JSON.parse encryption.decrypt obj @log.info "DM | Found and attached user-specific arguments to #{ userId }, #{ ruleId }, #{ modId }" catch err @log.warn "DM | Error during parsing of user-specific arguments for #{ userId }, #{ ruleId }, #{ modId }" diff --git a/coffee/encryption.coffee b/coffee/encryption.coffee new file mode 100644 index 0000000..6f94bb9 --- /dev/null +++ b/coffee/encryption.coffee @@ -0,0 +1,29 @@ +### + +Encryption +=============== +> Handles RSA encryption and decryption of user specific parameters. +### + +# **Loads Modules:** + +# - [cryptico](https://github.com/wwwtyro/cryptico) +cryptico = require 'my-cryptico' + +exports = module.exports = ( args ) => + @log = args.logger + @oPrivateRSAkey = cryptico.generateRSAKey args[ 'keygen' ], 1024 + @strPublicKey = cryptico.publicKeyString @oPrivateRSAkey + @log.info "DM | Public Key generated: #{ @strPublicKey }" + module.exports + +exports.getPublicKey = () => + @strPublicKey + +exports.encrypt = ( plainText ) => + oEncrypted = cryptico.encrypt plainText, @strPublicKey + oEncrypted.cipher + +exports.decrypt = ( strEncrypted ) => + oDecrypted = cryptico.decrypt strEncrypted, @oPrivateRSAkey + oDecrypted.plaintext diff --git a/coffee/event-poller.coffee b/coffee/event-poller.coffee index 08daa20..32b98df 100644 --- a/coffee/event-poller.coffee +++ b/coffee/event-poller.coffee @@ -8,11 +8,13 @@ Dynamic Modules # **Loads Modules:** -# - [Logging](logging.html), [Persistence](persistence.html) +# - [Logging](logging.html), [Persistence](persistence.html), +# [Encryption](encryption.html) # and [Dynamic Modules](dynamic-modules.html) logger = require './logging' db = require './persistence' dynmod = require './dynamic-modules' +encryption = require './encryption' # If we do not receive all required arguments we shut down immediately if process.argv.length < 8 @@ -33,6 +35,9 @@ log.info 'EP | Event Poller starts up' db logger: log dynmod logger: log + +encryption + logger: log keygen: process.argv[ 7 ] # Initialize module local variables and diff --git a/coffee/persistence.coffee b/coffee/persistence.coffee index 5c6ae58..2d0e36b 100644 --- a/coffee/persistence.coffee +++ b/coffee/persistence.coffee @@ -345,6 +345,22 @@ class IndexedModules @log.info "DB | (IdxedMods) #{ @setname }.getUserArgumentsFunctions( #{ userId }, #{ ruleId }, #{ mId } )" @db.get "#{ @setname }:#{ userId }:#{ ruleId }:#{ mId }:functions", cb + getAllModuleUserArguments: ( userId, ruleId, mId, cb ) => + @log.info "DB | (IdxedMods) #{ @setname }.getAllModuleUserArguments( #{ userId }, #{ ruleId }, #{ mId } )" + @db.smembers "#{ @setname }:#{ userId }:#{ ruleId }:#{ mId }:functions", ( err, obj ) => + sem = obj.length + console.log 'getAllModuleUserArguments' + console.log obj + oAnswer = {} + for func in obj + fRegisterFunction = ( func ) => + ( err, obj ) => + if obj + oAnswer[ func ] = obj + if --sem is 0 + cb null, oAnswer + @db.get "#{ @setname }:#{ userId }:#{ ruleId }:#{ mId }:function:#{ func }", fRegisterFunction func + getUserArguments: ( userId, ruleId, mId, funcId, cb ) => @log.info "DB | (IdxedMods) #{ @setname }.getUserArguments( #{ userId }, #{ ruleId }, #{ mId }, #{ funcId } )" @db.get "#{ @setname }:#{ userId }:#{ ruleId }:#{ mId }:function:#{ funcId }", cb diff --git a/coffee/webapi-eca.coffee b/coffee/webapi-eca.coffee index 9f6a3f3..9adbf36 100644 --- a/coffee/webapi-eca.coffee +++ b/coffee/webapi-eca.coffee @@ -30,6 +30,9 @@ engine = require './engine' # - [HTTP Listener](http-listener.html) http = require './http-listener' +# - [Encryption](encryption.html) +encryption = require './encryption' + # - [Event Poller](event-poller.html) *(will be forked into a child process)* nameEP = 'event-poller' @@ -134,6 +137,8 @@ init = => #FIXME this has to come from user input for security reasons: args[ 'keygen' ] = conf.getKeygenPassphrase() args[ 'webhooks' ] = conf.fetchProp 'webhooks' + + encryption args @log.info 'RS | Initialzing DB' db args diff --git a/js/components-manager.js b/js/components-manager.js index f4dc21c..544908e 100644 --- a/js/components-manager.js +++ b/js/components-manager.js @@ -10,12 +10,14 @@ Components Manager */ (function() { - var commandFunctions, db, dynmod, eventEmitter, events, exports, forgeModule, fs, getModuleParams, getModules, hasRequiredParams, path; + var commandFunctions, db, dynmod, encryption, eventEmitter, events, exports, forgeModule, fs, getModuleParams, getModuleUserArguments, getModuleUserParams, getModules, hasRequiredParams, path, storeModule, storeRule; db = require('./persistence'); dynmod = require('./dynamic-modules'); + encryption = require('./encryption'); + fs = require('fs'); path = require('path'); @@ -221,54 +223,140 @@ Components Manager } }; + getModuleUserParams = function(user, oPayload, dbMod, callback) { + var answ; + answ = hasRequiredParams(['id'], oPayload); + if (answ.code !== 200) { + return callback(answ); + } else { + return dbMod.getUserParams(oPayload.id, user.username, function(err, str) { + var name, oParam, oParams; + oParams = JSON.parse(str); + for (name in oParams) { + oParam = oParams[name]; + if (!oParam.shielded) { + oParam.value = encryption.decrypt(oParam.value); + } + } + answ.message = JSON.stringify(oParams); + return callback(answ); + }); + } + }; + + getModuleUserArguments = function(user, oPayload, dbMod, callback) { + var answ; + answ = hasRequiredParams(['ruleId', 'moduleId'], oPayload); + if (answ.code !== 200) { + return callback(answ); + } else { + return dbMod.getAllModuleUserArguments(user.username, oPayload.ruleId, oPayload.moduleId, function(err, oPayload) { + answ.message = oPayload; + return callback(answ); + }); + } + }; + forgeModule = (function(_this) { return function(user, oPayload, dbMod, callback) { - var answ, i; + var answ; answ = hasRequiredParams(['id', 'params', 'lang', 'data'], oPayload); if (answ.code !== 200) { return callback(answ); } else { - i = 0; - return dbMod.getModule(oPayload.id, function(err, mod) { - var src; - if (mod) { - answ.code = 409; - answ.message = 'Module name already existing: ' + oPayload.id; - return callback(answ); - } else { - src = oPayload.data; - return dynmod.compileString(src, user.username, 'dummyRule', oPayload.id, oPayload.lang, null, function(cm) { - var funcs, id, name, _ref; - answ = cm.answ; - if (answ.code === 200) { - funcs = []; - _ref = cm.module; - for (name in _ref) { - id = _ref[name]; - funcs.push(name); - } - _this.log.info("CM | Storing new module with functions " + (funcs.join(', '))); - answ.message = " Module " + oPayload.id + " successfully stored! Found following function(s): " + funcs; - oPayload.functions = JSON.stringify(funcs); - oPayload.functionArgs = JSON.stringify(cm.funcParams); - dbMod.storeModule(user.username, oPayload); - if (oPayload["public"] === 'true') { - dbMod.publish(oPayload.id); - } - } + if (oPayload.overwrite) { + return storeModule(user, oPayload, dbMod, callback); + } else { + return dbMod.getModule(oPayload.id, function(err, mod) { + if (mod) { + answ.code = 409; + answ.message = 'Module name already existing: ' + oPayload.id; return callback(answ); - }); - } - }); + } else { + return storeModule(user, oPayload, dbMod, callback); + } + }); + } } }; })(this); + storeModule = (function(_this) { + return function(user, oPayload, dbMod, callback) { + var src; + src = oPayload.data; + return dynmod.compileString(src, user.username, 'dummyRule', oPayload.id, oPayload.lang, null, function(cm) { + var answ, funcs, id, name, _ref; + answ = cm.answ; + if (answ.code === 200) { + funcs = []; + _ref = cm.module; + for (name in _ref) { + id = _ref[name]; + funcs.push(name); + } + _this.log.info("CM | Storing new module with functions " + (funcs.join(', '))); + answ.message = " Module " + oPayload.id + " successfully stored! Found following function(s): " + funcs; + oPayload.functions = JSON.stringify(funcs); + oPayload.functionArgs = JSON.stringify(cm.funcParams); + dbMod.storeModule(user.username, oPayload); + if (oPayload["public"] === 'true') { + dbMod.publish(oPayload.id); + } + } + return callback(answ); + }); + }; + })(this); + + storeRule = (function(_this) { + return function(user, oPayload, callback) { + var arr, epModId, id, oParams, params, rule, strRule; + rule = { + id: oPayload.id, + event: oPayload.event, + event_interval: oPayload.event_interval, + conditions: oPayload.conditions, + actions: oPayload.actions + }; + strRule = JSON.stringify(rule); + db.storeRule(rule.id, strRule); + db.linkRule(rule.id, user.username); + db.activateRule(rule.id, user.username); + if (oPayload.event_params) { + epModId = rule.event.split(' -> ')[0]; + db.eventPollers.storeUserParams(epModId, user.username, JSON.stringify(oPayload.event_params)); + } + oParams = oPayload.action_params; + for (id in oParams) { + params = oParams[id]; + db.actionInvokers.storeUserParams(id, user.username, JSON.stringify(params)); + } + oParams = oPayload.action_functions; + for (id in oParams) { + params = oParams[id]; + arr = id.split(' -> '); + db.actionInvokers.storeUserArguments(user.username, rule.id, arr[0], arr[1], JSON.stringify(params)); + } + db.resetLog(user.username, rule.id); + db.appendLog(user.username, rule.id, "INIT", "Rule '" + rule.id + "' initialized"); + eventEmitter.emit('rule', { + event: 'new', + user: user.username, + rule: rule + }); + return callback({ + code: 200, + message: "Rule '" + rule.id + "' stored and activated!" + }); + }; + })(this); + commandFunctions = { get_public_key: function(user, oPayload, callback) { return callback({ code: 200, - message: dynmod.getPublicKey() + message: encryption.getPublicKey() }); }, get_event_pollers: function(user, oPayload, callback) { @@ -285,6 +373,12 @@ Components Manager get_event_poller_params: function(user, oPayload, callback) { return getModuleParams(user, oPayload, db.eventPollers, callback); }, + get_event_poller_user_params: function(user, oPayload, callback) { + return getModuleUserParams(user, oPayload, db.eventPollers, callback); + }, + get_event_poller_user_arguments: function(user, oPayload, callback) { + return getModuleUserArguments(user, oPayload, db.eventPollers, callback); + }, forge_event_poller: function(user, oPayload, callback) { return forgeModule(user, oPayload, db.eventPollers, callback); }, @@ -321,7 +415,13 @@ Components Manager get_action_invoker_params: function(user, oPayload, callback) { return getModuleParams(user, oPayload, db.actionInvokers, callback); }, - get_action_invoker_function_params: function(user, oPayload, callback) { + get_action_invoker_user_params: function(user, oPayload, callback) { + return getModuleUserParams(user, oPayload, db.actionInvokers, callback); + }, + get_action_invoker_user_arguments: function(user, oPayload, callback) { + return getModuleUserArguments(user, oPayload, db.actionInvokers, callback); + }, + get_action_invoker_function_arguments: function(user, oPayload, callback) { var answ; answ = hasRequiredParams(['id'], oPayload); if (answ.code !== 200) { @@ -359,6 +459,20 @@ Components Manager }); }); }, + get_rule: function(user, oPayload, callback) { + var answ; + answ = hasRequiredParams(['id'], oPayload); + if (answ.code !== 200) { + return callback(answ); + } else { + return db.getRule(oPayload.id, function(err, obj) { + return callback({ + code: 200, + message: obj + }); + }); + } + }, get_rule_log: function(user, oPayload, callback) { var answ; answ = hasRequiredParams(['id'], oPayload); @@ -379,54 +493,21 @@ Components Manager if (answ.code !== 200) { return callback(answ); } else { - return db.getRule(oPayload.id, function(err, oExisting) { - var arr, epModId, id, oParams, params, rule, strRule; - if (oExisting !== null) { - answ = { - code: 409, - message: 'Rule name already existing!' + if (oPayload.overwrite) { + return storeRule(user, oPayload, callback); + } else { + return db.getRule(oPayload.id, (function(_this) { + return function(err, mod) { + if (mod) { + answ.code = 409; + answ.message = 'Rule name already existing: ' + oPayload.id; + return callback(answ); + } else { + return storeRule(user, oPayload, callback); + } }; - } else { - rule = { - id: oPayload.id, - event: oPayload.event, - event_interval: oPayload.event_interval, - conditions: oPayload.conditions, - actions: oPayload.actions - }; - strRule = JSON.stringify(rule); - db.storeRule(rule.id, strRule); - db.linkRule(rule.id, user.username); - db.activateRule(rule.id, user.username); - if (oPayload.event_params) { - epModId = rule.event.split(' -> ')[0]; - db.eventPollers.storeUserParams(epModId, user.username, oPayload.event_params); - } - oParams = oPayload.action_params; - for (id in oParams) { - params = oParams[id]; - db.actionInvokers.storeUserParams(id, user.username, JSON.stringify(params)); - } - oParams = oPayload.action_functions; - for (id in oParams) { - params = oParams[id]; - arr = id.split(' -> '); - db.actionInvokers.storeUserArguments(user.username, rule.id, arr[0], arr[1], JSON.stringify(params)); - } - db.resetLog(user.username, rule.id); - db.appendLog(user.username, rule.id, "INIT", "Rule '" + rule.id + "' initialized"); - eventEmitter.emit('rule', { - event: 'new', - user: user.username, - rule: rule - }); - answ = { - code: 200, - message: "Rule '" + rule.id + "' stored and activated!" - }; - } - return callback(answ); - }); + })(this)); + } } }, delete_rule: function(user, oPayload, callback) { diff --git a/js/dynamic-modules.js b/js/dynamic-modules.js index 07c1c6d..264ec10 100644 --- a/js/dynamic-modules.js +++ b/js/dynamic-modules.js @@ -9,10 +9,12 @@ Dynamic Modules */ (function() { - var cryptico, cryptoJS, cs, db, exports, fTryToLoadModule, getFunctionParamNames, importio, logFunction, needle, regexpComments, request, vm; + var cryptoJS, cs, db, encryption, exports, fTryToLoadModule, getFunctionParamNames, importio, logFunction, needle, regexpComments, request, vm; db = require('./persistence'); + encryption = require('./encryption'); + vm = require('vm'); needle = require('needle'); @@ -21,8 +23,6 @@ Dynamic Modules cs = require('coffee-script'); - cryptico = require('my-cryptico'); - cryptoJS = require('crypto-js'); importio = require('import-io').client; @@ -38,26 +38,12 @@ Dynamic Modules exports = module.exports = (function(_this) { return function(args) { - var numBits, passPhrase; _this.log = args.logger; - if (!_this.strPublicKey && args['keygen']) { - db(args); - passPhrase = args['keygen']; - numBits = 1024; - _this.oPrivateRSAkey = cryptico.generateRSAKey(passPhrase, numBits); - _this.strPublicKey = cryptico.publicKeyString(_this.oPrivateRSAkey); - _this.log.info("DM | Public Key generated: " + _this.strPublicKey); - } + db(args); return module.exports; }; })(this); - exports.getPublicKey = (function(_this) { - return function() { - return _this.strPublicKey; - }; - })(this); - logFunction = function(uId, rId, mId) { return function(msg) { return db.appendLog(uId, rId, mId, msg); @@ -110,17 +96,21 @@ Dynamic Modules _this.log.info("DM | Trying to fetch user specific module '" + modId + "' paramters for user '" + userId + "'"); if (dbMod) { return dbMod.getUserParams(modId, userId, function(err, obj) { - var oDecrypted; + var name, oParam, oParams, _ref; try { - oDecrypted = cryptico.decrypt(obj, _this.oPrivateRSAkey); - obj = JSON.parse(oDecrypted.plaintext); + oParams = {}; + _ref = JSON.parse(obj); + for (name in _ref) { + oParam = _ref[name]; + oParams[name] = encryption.decrypt(oParam.value); + } _this.log.info("DM | Loaded user defined params for " + userId + ", " + ruleId + ", " + modId); } catch (_error) { err = _error; _this.log.warn("DM | Error during parsing of user defined params for " + userId + ", " + ruleId + ", " + modId); _this.log.warn(err); } - return fTryToLoadModule(userId, ruleId, modId, src, dbMod, obj, cb); + return fTryToLoadModule(userId, ruleId, modId, src, dbMod, oParams, cb); }); } else { return fTryToLoadModule(userId, ruleId, modId, src, dbMod, null, cb); @@ -174,11 +164,9 @@ Dynamic Modules oFuncArgs = {}; for (func in oFuncParams) { dbMod.getUserArguments(userId, ruleId, modId, func, function(err, obj) { - var oDecrypted; if (obj) { try { - oDecrypted = cryptico.decrypt(obj, _this.oPrivateRSAkey); - oFuncArgs[func] = JSON.parse(oDecrypted.plaintext); + oFuncArgs[func] = JSON.parse(encryption.decrypt(obj)); return _this.log.info("DM | Found and attached user-specific arguments to " + userId + ", " + ruleId + ", " + modId); } catch (_error) { err = _error; diff --git a/js/encryption.js b/js/encryption.js new file mode 100644 index 0000000..f54e09f --- /dev/null +++ b/js/encryption.js @@ -0,0 +1,47 @@ +// Generated by CoffeeScript 1.7.1 + +/* + +Encryption +=============== +> Handles RSA encryption and decryption of user specific parameters. + */ + +(function() { + var cryptico, exports; + + cryptico = require('my-cryptico'); + + exports = module.exports = (function(_this) { + return function(args) { + _this.log = args.logger; + _this.oPrivateRSAkey = cryptico.generateRSAKey(args['keygen'], 1024); + _this.strPublicKey = cryptico.publicKeyString(_this.oPrivateRSAkey); + _this.log.info("DM | Public Key generated: " + _this.strPublicKey); + return module.exports; + }; + })(this); + + exports.getPublicKey = (function(_this) { + return function() { + return _this.strPublicKey; + }; + })(this); + + exports.encrypt = (function(_this) { + return function(plainText) { + var oEncrypted; + oEncrypted = cryptico.encrypt(plainText, _this.strPublicKey); + return oEncrypted.cipher; + }; + })(this); + + exports.decrypt = (function(_this) { + return function(strEncrypted) { + var oDecrypted; + oDecrypted = cryptico.decrypt(strEncrypted, _this.oPrivateRSAkey); + return oDecrypted.plaintext; + }; + })(this); + +}).call(this); diff --git a/js/event-poller.js b/js/event-poller.js index fe3ad19..eb36613 100644 --- a/js/event-poller.js +++ b/js/event-poller.js @@ -9,7 +9,7 @@ Dynamic Modules */ (function() { - var db, dynmod, fCallFunction, fCheckAndRun, fLoadModule, isRunning, listUserModules, log, logconf, logger, pollLoop; + var db, dynmod, encryption, fCallFunction, fCheckAndRun, fLoadModule, isRunning, listUserModules, log, logconf, logger, pollLoop; logger = require('./logging'); @@ -17,6 +17,8 @@ Dynamic Modules dynmod = require('./dynamic-modules'); + encryption = require('./encryption'); + if (process.argv.length < 8) { console.error('Not all arguments have been passed!'); process.exit(); @@ -42,6 +44,10 @@ Dynamic Modules }); dynmod({ + logger: log + }); + + encryption({ logger: log, keygen: process.argv[7] }); diff --git a/js/persistence.js b/js/persistence.js index 4e69134..b618715 100644 --- a/js/persistence.js +++ b/js/persistence.js @@ -257,6 +257,7 @@ Persistence this.log = log; this.deleteUserArguments = __bind(this.deleteUserArguments, this); this.getUserArguments = __bind(this.getUserArguments, this); + this.getAllModuleUserArguments = __bind(this.getAllModuleUserArguments, this); this.getUserArgumentsFunctions = __bind(this.getUserArgumentsFunctions, this); this.storeUserArguments = __bind(this.storeUserArguments, this); this.deleteUserParams = __bind(this.deleteUserParams, this); @@ -438,6 +439,35 @@ Persistence return this.db.get("" + this.setname + ":" + userId + ":" + ruleId + ":" + mId + ":functions", cb); }; + IndexedModules.prototype.getAllModuleUserArguments = function(userId, ruleId, mId, cb) { + this.log.info("DB | (IdxedMods) " + this.setname + ".getAllModuleUserArguments( " + userId + ", " + ruleId + ", " + mId + " )"); + return this.db.smembers("" + this.setname + ":" + userId + ":" + ruleId + ":" + mId + ":functions", (function(_this) { + return function(err, obj) { + var fRegisterFunction, func, oAnswer, sem, _i, _len, _results; + sem = obj.length; + console.log('getAllModuleUserArguments'); + console.log(obj); + oAnswer = {}; + _results = []; + for (_i = 0, _len = obj.length; _i < _len; _i++) { + func = obj[_i]; + fRegisterFunction = function(func) { + return function(err, obj) { + if (obj) { + oAnswer[func] = obj; + } + if (--sem === 0) { + return cb(null, oAnswer); + } + }; + }; + _results.push(_this.db.get("" + _this.setname + ":" + userId + ":" + ruleId + ":" + mId + ":function:" + func, fRegisterFunction(func))); + } + return _results; + }; + })(this)); + }; + IndexedModules.prototype.getUserArguments = function(userId, ruleId, mId, funcId, cb) { this.log.info("DB | (IdxedMods) " + this.setname + ".getUserArguments( " + userId + ", " + ruleId + ", " + mId + ", " + funcId + " )"); return this.db.get("" + this.setname + ":" + userId + ":" + ruleId + ":" + mId + ":function:" + funcId, cb); diff --git a/js/webapi-eca.js b/js/webapi-eca.js index e02cb30..6e1bab2 100644 --- a/js/webapi-eca.js +++ b/js/webapi-eca.js @@ -13,7 +13,7 @@ WebAPI-ECA Engine */ (function() { - var argv, cm, conf, cp, db, engine, fs, http, init, logconf, logger, nameEP, opt, optimist, path, procCmds, shutDown, usage; + var argv, cm, conf, cp, db, encryption, engine, fs, http, init, logconf, logger, nameEP, opt, optimist, path, procCmds, shutDown, usage; logger = require('./logging'); @@ -27,6 +27,8 @@ WebAPI-ECA Engine http = require('./http-listener'); + encryption = require('./encryption'); + nameEP = 'event-poller'; fs = require('fs'); @@ -147,6 +149,7 @@ WebAPI-ECA Engine args['db-port'] = parseInt(argv.d || conf.getDbPort()); args['keygen'] = conf.getKeygenPassphrase(); args['webhooks'] = conf.fetchProp('webhooks'); + encryption(args); _this.log.info('RS | Initialzing DB'); db(args); return db.isConnected(function(err) { diff --git a/webpages/handlers/coffee/edit_modules.coffee b/webpages/handlers/coffee/edit_modules.coffee index a79f8a6..7d4e84e 100644 --- a/webpages/handlers/coffee/edit_modules.coffee +++ b/webpages/handlers/coffee/edit_modules.coffee @@ -11,14 +11,16 @@ fOnLoad = () -> if err.status is 401 window.location.href = 'forge?page=edit_modules' else - if err.responseText is '' - msg = 'No Response from Server!' - else - try - oErr = JSON.parse err.responseText - msg = oErr.message - $( '#info' ).text errMsg + msg - $( '#info' ).attr 'class', 'error' + fDelayed = () -> + if err.responseText is '' + msg = 'No Response from Server!' + else + try + oErr = JSON.parse err.responseText + msg = oErr.message + $( '#info' ).text errMsg + msg + $( '#info' ).attr 'class', 'error' + setTimeout fDelayed, 500 fFetchModules = () -> if $( '#module_type' ).val() is 'Event Poller' @@ -56,9 +58,8 @@ fOnLoad = () -> cmd = 'delete_action_invoker' data = command: cmd - payload: + payload: JSON.stringify id: modName - data.payload = JSON.stringify data.payload $.post( '/usercommand', data ) .done fFetchModules .fail fErrHandler 'Could not delete module! ' @@ -66,8 +67,8 @@ fOnLoad = () -> $( '#tableModules' ).on 'click', 'img.log', () -> modName = encodeURIComponent $( 'div', $( this ).closest( 'tr' )).text() if $( '#module_type' ).val() is 'Event Poller' - window.location.href = 'forge?page=forge_event_poller&id=' + modName + window.location.href = 'forge?page=forge_module&type=event_poller&id=' + modName else - window.location.href = 'forge?page=forge_action_invoker&id=' + modName + window.location.href = 'forge?page=forge_module&type=action_invoker&id=' + modName window.addEventListener 'load', fOnLoad, true diff --git a/webpages/handlers/coffee/edit_rules.coffee b/webpages/handlers/coffee/edit_rules.coffee index 1a23b9a..be67715 100644 --- a/webpages/handlers/coffee/edit_rules.coffee +++ b/webpages/handlers/coffee/edit_rules.coffee @@ -50,9 +50,8 @@ fOnLoad = () -> $( '#log_col' ).text "" data = command: 'delete_rule' - payload: + payload: JSON.stringify id: ruleName - data.payload = JSON.stringify data.payload $.post( '/usercommand', data ) .done fFetchRules .fail fErrHandler 'Could not delete rule! ' @@ -65,47 +64,12 @@ fOnLoad = () -> ruleName = $( 'div', $( this ).closest( 'tr' )).text() data = command: 'get_rule_log' - payload: + payload: JSON.stringify id: ruleName - data.payload = JSON.stringify data.payload $.post( '/usercommand', data ) .done ( data ) -> log = data.message.replace new RegExp("\n", 'g'), "
" $( '#log_col' ).html "

#{ ruleName } Log:

#{ log }" .fail fErrHandler 'Could not get rule log! ' - # Add parameter list functionality - fChangeInputVisibility = () -> - $( '#tableParams tr' ).each ( id ) -> - if $( this ).is ':last-child' or $( this ).is ':only-child' - $( 'img', this ).hide() - $( 'input[type=checkbox]', this ).hide() - else - $( 'img', this ).show() - $( 'input[type=checkbox]', this ).show() - - $( '#tableParams' ).on 'click', 'img', () -> - par = $( this ).closest 'tr' - if not par.is ':last-child' - par.remove() - fChangeInputVisibility() - - $( '#tableParams' ).on 'keyup', 'input', ( e ) -> - code = e.keyCode or e.which - if code isnt 9 - par = $( this ).closest 'tr' - if par.is ':last-child' - tr = $ '' - img = $( '' ).attr( 'title', 'Remove?').attr 'src', 'red_cross_small.png' - cb = $( '' ).attr( 'type', 'checkbox' ).attr 'title', 'Password shielded input?' - inp = $( '' ).attr( 'type', 'text' ).attr 'class', 'textinput' - tr.append $( '' ).append img - tr.append $( '' ).append cb - tr.append $( '' ).append inp - par.parent().append tr - fChangeInputVisibility() - else if $( this ).val() is '' and not par.is ':only-child' - par.remove() - - fChangeInputVisibility() window.addEventListener 'load', fOnLoad, true diff --git a/webpages/handlers/coffee/forge_action_invoker.coffee b/webpages/handlers/coffee/forge_action_invoker.coffee deleted file mode 100644 index 24600da..0000000 --- a/webpages/handlers/coffee/forge_action_invoker.coffee +++ /dev/null @@ -1,110 +0,0 @@ - -fOnLoad = () -> - document.title = 'Forge Action Invoker' - $( '#pagetitle' ).text "{{{user.username}}}, forge your custom action invoker!" - - # Setup the ACE editor - editor = ace.edit "editor" - editor.setTheme "ace/theme/monokai" - editor.getSession().setMode "ace/mode/coffee" - editor.setShowPrintMargin false - editor.session.setUseSoftTabs false - - $( '#editor_mode' ).change ( el ) -> - if $( this ).val() is 'CoffeeScript' - editor.getSession().setMode "ace/mode/coffee" - else - editor.getSession().setMode "ace/mode/javascript" - - # Add parameter list functionality - fChangeInputVisibility = () -> - $( '#tableParams tr' ).each ( id ) -> - if $( this ).is ':last-child' or $( this ).is ':only-child' - $( 'img', this ).hide() - $( 'input[type=checkbox]', this ).hide() - else - $( 'img', this ).show() - $( 'input[type=checkbox]', this ).show() - - $( '#tableParams' ).on 'click', 'img', () -> - par = $( this ).closest 'tr' - if not par.is ':last-child' - par.remove() - fChangeInputVisibility() - - $( '#tableParams' ).on 'keyup', 'input', ( e ) -> - code = e.keyCode or e.which - if code isnt 9 - par = $( this ).closest( 'tr' ) - if par.is ':last-child' - tr = $ '' - img = $( '' ).attr( 'title', 'Remove?').attr 'src', 'red_cross_small.png' - cb = $( '' ).attr( 'type', 'checkbox' ).attr 'title', 'Password shielded input?' - inp = $( '' ).attr( 'type', 'text' ).attr 'class', 'textinput' - tr.append( $( '' ).append img ) - tr.append( $( '' ).append cb ) - tr.append( $( '' ).append inp ) - par.parent().append tr - fChangeInputVisibility() - else if $( this ).val() is '' and not par.is ':only-child' - par.remove() - - fChangeInputVisibility() - - # Add submit button logic - $( '#but_submit' ).click () -> - if $( '#input_id' ).val() is '' - alert 'Please enter an action invoker name!' - else - listParams = {} - $( '#tableParams tr' ).each () -> - val = $( 'input.textinput', this ).val() - shld = $( 'input[type=checkbox]', this ).is ':checked' - if val isnt "" - listParams[val] = shld - true - obj = - command: 'forge_action_invoker' - payload: - id: $( '#input_id' ).val() - lang: $( '#editor_mode' ).val() - public: $( '#is_public' ).is ':checked' - data: editor.getValue() - params: JSON.stringify listParams - obj.payload = JSON.stringify obj.payload - window.scrollTo 0, 0 - $.post( '/usercommand', obj ) - .done ( data ) -> - $( '#info' ).text data.message - $( '#info' ).attr 'class', 'success' - .fail ( err ) -> - if err.status is 401 - window.location.href = 'forge?page=forge_action_invoker' - else - fDelayed = () -> - if err.responseText is '' - msg = 'No Response from Server!' - else - try - oErr = JSON.parse err.responseText - msg = oErr.message - $( '#info' ).text 'Action Invoker not stored! ' + msg - $( '#info' ).attr 'class', 'error' - setTimeout fDelayed, 500 - - - # EDIT MODULES - - arrParams = window.location.search.substring(1).split '&' - id = '' - for param in arrParams - arrKV = param.split '=' - if arrKV[ 0 ] is 'id' - id = decodeURIComponent arrKV[ 1 ] - if id isnt '' - # TODO we have an idea so we want to edit this module! - console.log id - - - -window.addEventListener 'load', fOnLoad, true diff --git a/webpages/handlers/coffee/forge_event_poller.coffee b/webpages/handlers/coffee/forge_event_poller.coffee deleted file mode 100644 index 9827841..0000000 --- a/webpages/handlers/coffee/forge_event_poller.coffee +++ /dev/null @@ -1,95 +0,0 @@ - -fOnLoad = () -> - document.title = 'Forge Event Poller' - $( '#pagetitle' ).text "{{{user.username}}}, forge your custom event poller!" - - # Setup the ACE editor - editor = ace.edit "editor" - editor.setTheme "ace/theme/monokai" - editor.getSession().setMode "ace/mode/coffee" - editor.setShowPrintMargin false - - $( '#editor_mode' ).change ( el ) -> - if $( this ).val() is 'CoffeeScript' - editor.getSession().setMode "ace/mode/coffee" - else - editor.getSession().setMode "ace/mode/javascript" - - # Add parameter list functionality - fChangeInputVisibility = () -> - $( '#tableParams tr' ).each ( id ) -> - if $( this ).is ':last-child' or $( this ).is ':only-child' - $( 'img', this ).hide() - $( 'input[type=checkbox]', this ).hide() - else - $( 'img', this ).show() - $( 'input[type=checkbox]', this ).show() - - $( '#tableParams' ).on 'click', 'img', () -> - par = $( this ).closest 'tr' - if not par.is ':last-child' - par.remove() - fChangeInputVisibility() - - $( '#tableParams' ).on 'keyup', 'input', ( e ) -> - code = e.keyCode or e.which - if code isnt 9 - par = $( this ).closest( 'tr' ) - if par.is ':last-child' - tr = $ '' - img = $( '' ).attr( 'title', 'Remove?').attr 'src', 'red_cross_small.png' - cb = $( '' ).attr( 'type', 'checkbox' ).attr 'title', 'Password shielded input?' - inp = $( '' ).attr( 'type', 'text' ).attr 'class', 'textinput' - tr.append( $( '' ).append img ) - tr.append( $( '' ).append cb ) - tr.append( $( '' ).append inp ) - tr.append $( '' ) - par.parent().append tr - fChangeInputVisibility() - else if $( this ).val() is '' and not par.is ':only-child' - par.remove() - - fChangeInputVisibility() - - # Add submit button logic - $( '#but_submit' ).click () -> - if $( '#input_id' ).val() is '' - alert 'Please enter an event poller name!' - else - listParams = {} - $( '#tableParams tr' ).each () -> - val = $( 'input.textinput', this ).val() - shld = $( 'input[type=checkbox]', this ).is ':checked' - if val isnt "" - listParams[val] = shld - true - obj = - command: 'forge_event_poller' - payload: - id: $( '#input_id' ).val() - lang: $( '#editor_mode' ).val() - public: $( '#is_public' ).is ':checked' - data: editor.getValue() - params: JSON.stringify listParams - obj.payload = JSON.stringify obj.payload - window.scrollTo 0, 0 - $.post( '/usercommand', obj ) - .done ( data ) -> - $( '#info' ).text data.message - $( '#info' ).attr 'class', 'success' - .fail ( err ) -> - if err.status is 401 - window.location.href = 'forge?page=forge_event_poller' - else - fDelayed = () -> - if err.responseText is '' - msg = 'No Response from Server!' - else - try - oErr = JSON.parse err.responseText - msg = oErr.message - $( '#info' ).text 'Event Poller not stored! ' + msg - $( '#info' ).attr 'class', 'error' - setTimeout fDelayed, 500 - -window.addEventListener 'load', fOnLoad, true diff --git a/webpages/handlers/coffee/forge_module.coffee b/webpages/handlers/coffee/forge_module.coffee new file mode 100644 index 0000000..2e91576 --- /dev/null +++ b/webpages/handlers/coffee/forge_module.coffee @@ -0,0 +1,175 @@ +# Fetch the search string and transform it into an object for easy access +arrParams = window.location.search.substring(1).split '&' +oParams = {} +for param in arrParams + arrKV = param.split '=' + oParams[ arrKV[ 0 ] ] = arrKV[ 1 ] + +if oParams.type is 'event_poller' + moduleName = 'Event Poller' +else + moduleName = 'Action Invoker' + oParams.type = 'action_invoker' +if oParams.id + oParams.id = decodeURIComponent oParams.id + +fErrHandler = ( errMsg ) -> + ( err ) -> + if err.status is 401 + window.location.href = "forge?page=forge_module?type=#{ oParams.type }" + else + $( '#log_col' ).text "" + fDelayed = () -> + if err.responseText is '' + msg = 'No Response from Server!' + else + try + oErr = JSON.parse err.responseText + msg = oErr.message + $( '#info' ).text errMsg + msg + $( '#info' ).attr 'class', 'error' + setTimeout fDelayed, 500 + +fOnLoad = () -> + document.title = "Forge #{ moduleName }" + $( '#pagetitle' ).text "{{{user.username}}}, forge your custom #{ moduleName }!" + + # Setup the ACE editor + editor = ace.edit "editor" + editor.setTheme "ace/theme/monokai" + editor.getSession().setMode "ace/mode/coffee" + editor.setShowPrintMargin false + editor.session.setUseSoftTabs false + + $( '#editor_mode' ).change ( el ) -> + if $( this ).val() is 'CoffeeScript' + editor.getSession().setMode "ace/mode/coffee" + else + editor.getSession().setMode "ace/mode/javascript" + + # Add parameter list functionality + fChangeInputVisibility = () -> + $( '#tableParams tr' ).each ( id ) -> + if $( this ).is ':last-child' or $( this ).is ':only-child' + $( 'img', this ).hide() + $( 'input[type=checkbox]', this ).hide() + else + $( 'img', this ).show() + $( 'input[type=checkbox]', this ).show() + + fAddInputRow = ( tag ) -> + tr = $ '' + img = $( '' ).attr( 'title', 'Remove?').attr 'src', 'red_cross_small.png' + cb = $( '' ).attr( 'type', 'checkbox' ).attr 'title', 'Password shielded input?' + inp = $( '' ).attr( 'type', 'text' ).attr 'class', 'textinput' + tr.append( $( '' ).append img ) + tr.append( $( '' ).append cb ) + tr.append( $( '' ).append inp ) + tag.append tr + fChangeInputVisibility() + tr + + $( '#tableParams' ).on 'click', 'img', () -> + par = $( this ).closest 'tr' + if not par.is ':last-child' + par.remove() + fChangeInputVisibility() + + $( '#tableParams' ).on 'keyup', 'input', ( e ) -> + code = e.keyCode or e.which + if code isnt 9 + par = $( this ).closest( 'tr' ) + if par.is ':last-child' + fAddInputRow par.parent() + else if $( this ).val() is '' and not par.is ':only-child' + par.remove() + + fChangeInputVisibility() + + # Add submit button logic + $( '#but_submit' ).click () -> + if $( '#input_id' ).val() is '' + alert "Please enter an #{ moduleName } name!" + else + listParams = {} + $( '#tableParams tr' ).each () -> + val = $( 'input.textinput', this ).val() + shld = $( 'input[type=checkbox]', this ).is ':checked' + if val isnt "" + listParams[val] = shld + true + obj = + command: "forge_#{ oParams.type }" + payload: JSON.stringify + id: $( '#input_id' ).val() + lang: $( '#editor_mode' ).val() + public: $( '#is_public' ).is ':checked' + data: editor.getValue() + params: JSON.stringify listParams + fCheckOverwrite = ( obj ) -> + ( err ) -> + if err.status is 409 + if confirm 'Are you sure you want to overwrite the existing module?' + payl = JSON.parse obj.payload + payl.overwrite = true + obj.payload = JSON.stringify payl + $.post( '/usercommand', obj ) + .done ( data ) -> + $( '#info' ).text data.message + $( '#info' ).attr 'class', 'success' + alert "You need to update the rules that use this module in + order for the changes to be applied to them!" + .fail fErrHandler "#{ moduleName } not stored!" + else + fErrHandler( "#{ moduleName } not stored!" ) err + window.scrollTo 0, 0 + $.post( '/usercommand', obj ) + .done ( data ) -> + $( '#info' ).text data.message + $( '#info' ).attr 'class', 'success' + .fail fCheckOverwrite obj + + # EDIT MODULES + + fAddUserParam = ( param, shielded ) -> + tr = fAddInputRow $( '#tableParams' ) + $( 'input.textinput', tr ).val param + if shielded + $( 'input[type=checkbox]', tr ).prop 'checked', true + + if oParams.id + obj = + command: "get_full_#{ oParams.type }" + payload: JSON.stringify + id: oParams.id + + $.post( '/usercommand', obj ) + .done ( data ) -> + oMod = JSON.parse data.message + if oMod + fAddUserParam param, shielded for param, shielded of JSON.parse oMod.params + $( '#input_id' ).val oMod.id + $( '#editor_mode' ).val oMod.lang + if oMod.public is 'true' + $( '#is_public' ).prop 'checked', true + editor.setValue oMod.data + editor.moveCursorTo 0, 0 + fAddUserParam '', false + + .fail fErrHandler "Could not get module #{ oParams.id }!" + + else + # We add the standard template, params and names + editor.setValue $( "#template_#{ oParams.type }" ).text() + editor.moveCursorTo 0, 0 + if oParams.type is 'event_poller' + $( '#input_id' ).val 'EmailYak' + fAddUserParam 'apikey', true + fAddUserParam '', false + else + $( '#input_id' ).val 'ProBinder' + fAddUserParam 'username', false + fAddUserParam 'password', true + fAddUserParam '', false + +window.addEventListener 'load', fOnLoad, true diff --git a/webpages/handlers/coffee/forge_rule.coffee b/webpages/handlers/coffee/forge_rule.coffee index 39a45dc..2d6a1bf 100644 --- a/webpages/handlers/coffee/forge_rule.coffee +++ b/webpages/handlers/coffee/forge_rule.coffee @@ -1,5 +1,14 @@ -strPublicKey = '' +# Fetch the search string and transform it into an object for easy access +arrParams = window.location.search.substring(1).split '&' +oParams = {} +for param in arrParams + arrKV = param.split '=' + oParams[ arrKV[ 0 ] ] = arrKV[ 1 ] +if oParams.id + oParams.id = decodeURIComponent oParams.id + +strPublicKey = '' fPlaceAndPaintInterval = () -> $( '#input_interval' ).html 'Interval: @@ -40,9 +49,8 @@ fOnLoad = () -> arr = name.split ' -> ' obj = command: 'get_event_poller_params' - payload: - id: arr[0] - obj.payload = JSON.stringify( obj.payload ); + payload: JSON.stringify + id: arr[ 0 ] $.post( '/usercommand', obj ) .done ( data ) -> if data.message @@ -54,7 +62,7 @@ fOnLoad = () -> tr = $( '' ) tr.append $( '' ).css 'width', '20px' tr.append $( '' ).attr( 'class', 'key' ).text name - inp = $( '' ).attr 'id', "#{ name }" + inp = $( '' ) if shielded inp.attr( 'type', 'password' ) tr.append $( '' ).text( ' : ' ).append inp @@ -97,6 +105,7 @@ fOnLoad = () -> else fPlaceAndPaintInterval() + # Init Action Invoker obj = command: 'get_action_invokers' @@ -110,16 +119,16 @@ fOnLoad = () -> return fAppendActions = ( module, actions ) -> for act in actions - $( '#select_actions' ).append $( '