UNPKG

openhim-core

Version:

The OpenHIM core application that provides logging and routing of http requests

472 lines (444 loc) 16.3 kB
var Channel, Mediator, Q, atna, auditing, authorisation, constructError, logger, mask, maskPasswords, restoreMaskedPasswords, saveDefaultChannelConfig, semver, utils, validateConfig, validateConfigDef, validateConfigDefs, validateConfigField, indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; Channel = require('../model/channels').Channel; Mediator = require('../model/mediators').Mediator; Q = require('q'); logger = require('winston'); authorisation = require('./authorisation'); semver = require('semver'); atna = require('atna-audit'); utils = require("../utils"); auditing = require('../auditing'); mask = '**********'; maskPasswords = function(defs, config) { if (!config) { return; } return defs.forEach(function(d) { if (d.type === 'password' && config[d.param]) { if (d.array) { config[d.param] = config[d.param].map(function() { return mask; }); } else { config[d.param] = mask; } } if (d.type === 'struct' && config[d.param]) { return maskPasswords(d.template, config[d.param]); } }); }; restoreMaskedPasswords = function(defs, maskedConfig, config) { if (!maskedConfig || !config) { return; } return defs.forEach(function(d) { if (d.type === 'password' && maskedConfig[d.param] && config[d.param]) { if (d.array) { maskedConfig[d.param].forEach(function(p, i) { if (p === mask) { return maskedConfig[d.param][i] = config[d.param][i]; } }); } else { if (maskedConfig[d.param] === mask) { maskedConfig[d.param] = config[d.param]; } } } if (d.type === 'struct' && maskedConfig[d.param] && config[d.param]) { return restoreMaskedPasswords(d.template, maskedConfig[d.param], config[d.param]); } }); }; exports.getAllMediators = function*() { var err, error, m; if (!authorisation.inGroup('admin', this.authenticated)) { utils.logAndSetResponse(this, 403, "User " + this.authenticated.email + " is not an admin, API access to getAllMediators denied.", 'info'); return; } try { m = (yield Mediator.find().exec()); maskPasswords(m.configDefs, m.config); return this.body = m; } catch (error) { err = error; return logAndSetResponse(this, 500, "Could not fetch mediators via the API: " + err, 'error'); } }; exports.getMediator = function*(mediatorURN) { var err, error, result, urn; if (!authorisation.inGroup('admin', this.authenticated)) { utils.logAndSetResponse(this, 403, "User " + this.authenticated.email + " is not an admin, API access to getMediator denied.", 'info'); return; } urn = unescape(mediatorURN); try { result = (yield Mediator.findOne({ "urn": urn }).exec()); if (result === null) { return this.status = 404; } else { maskPasswords(result.configDefs, result.config); return this.body = result; } } catch (error) { err = error; return logAndSetResponse(this, 500, "Could not fetch mediator using UUID " + urn + " via the API: " + err, 'error'); } }; constructError = function(message, name) { var err; err = new Error(message); err.name = name; return err; }; validateConfigDef = function(def) { var j, len, ref, results, templateItem; if (def.type === 'struct' && !def.template) { throw constructError("Must specify a template for struct param '" + def.param + "'", 'ValidationError'); } else if (def.type === 'struct') { ref = def.template; results = []; for (j = 0, len = ref.length; j < len; j++) { templateItem = ref[j]; if (!templateItem.param) { throw constructError("Must specify field 'param' in template definition for param '" + def.param + "'", 'ValidationError'); } if (!templateItem.type) { throw constructError("Must specify field 'type' in template definition for param '" + def.param + "'", 'ValidationError'); } if (templateItem.type === 'struct') { throw constructError("May not recursively specify 'struct' in template definitions (param '" + def.param + "')", 'ValidationError'); } results.push(validateConfigDef(templateItem)); } return results; } else if (def.type === 'option') { if (!utils.typeIsArray(def.values)) { throw constructError("Expected field 'values' to be an array (option param '" + def.param + "')", 'ValidationError'); } if ((def.values == null) || def.values.length === 0) { throw constructError("Must specify a values array for option param '" + def.param + "'", 'ValidationError'); } } }; validateConfigDefs = function(configDefs) { var def, j, len, results; results = []; for (j = 0, len = configDefs.length; j < len; j++) { def = configDefs[j]; results.push(validateConfigDef(def)); } return results; }; exports.addMediator = function*() { var audit, err, error, existing, mediator, mediatorHost, param, ref, ref1, ref2, val; if (!authorisation.inGroup('admin', this.authenticated)) { utils.logAndSetResponse(this, 403, "User " + this.authenticated.email + " is not an admin, API access to addMediator denied.", 'info'); return; } try { mediator = this.request.body; if ((mediator != null ? (ref = mediator.endpoints) != null ? (ref1 = ref[0]) != null ? ref1.host : void 0 : void 0 : void 0) != null) { mediatorHost = mediator.endpoints[0].host; } else { mediatorHost = 'unknown'; } audit = atna.appActivityAudit(true, mediator.name, mediatorHost, 'system'); audit = atna.wrapInSyslog(audit); auditing.sendAuditEvent(audit, function() { return logger.info("Processed internal mediator start audit for: " + mediator.name + " - " + mediator.urn); }); if (!mediator.urn) { throw constructError('URN is required', 'ValidationError'); } if (!mediator.version || !semver.valid(mediator.version)) { throw constructError('Version is required. Must be in SemVer form x.y.z', 'ValidationError'); } if (mediator.configDefs) { validateConfigDefs(mediator.configDefs); if (mediator.config != null) { validateConfig(mediator.configDefs, mediator.config); } } existing = (yield Mediator.findOne({ urn: mediator.urn }).exec()); if (existing != null) { if (semver.gt(mediator.version, existing.version)) { if ((mediator.config != null) && (existing.config != null)) { ref2 = mediator.config; for (param in ref2) { val = ref2[param]; if (existing.config[param] != null) { mediator.config[param] = existing.config[param]; } } } (yield Mediator.findByIdAndUpdate(existing._id, mediator).exec()); } } else { if (!mediator.endpoints || mediator.endpoints.length < 1) { throw constructError('At least 1 endpoint is required', 'ValidationError'); } (yield Q.ninvoke(new Mediator(mediator), 'save')); } this.status = 201; return logger.info("User " + this.authenticated.email + " created mediator with urn " + mediator.urn); } catch (error) { err = error; if (err.name === 'ValidationError') { return utils.logAndSetResponse(this, 400, "Could not add Mediator via the API: " + err, 'error'); } else { return utils.logAndSetResponse(this, 500, "Could not add Mediator via the API: " + err, 'error'); } } }; exports.removeMediator = function*(urn) { var err, error; if (!authorisation.inGroup('admin', this.authenticated)) { utils.logAndSetResponse(this, 403, "User " + this.authenticated.email + " is not an admin, API access to removeMediator denied.", 'info'); return; } urn = unescape(urn); try { (yield Mediator.findOneAndRemove({ urn: urn }).exec()); this.body = "Mediator with urn " + urn + " has been successfully removed by " + this.authenticated.email; return logger.info("Mediator with urn " + urn + " has been successfully removed by " + this.authenticated.email); } catch (error) { err = error; return utils.logAndSetResponse(this, 500, "Could not remove Mediator by urn " + urn + " via the API: " + err, 'error'); } }; exports.heartbeat = function*(urn) { var err, error, heartbeat, mediator, update; if (!authorisation.inGroup('admin', this.authenticated)) { utils.logAndSetResponse(this, 403, "User " + this.authenticated.email + " is not an admin, API access to removeMediator denied.", 'info'); return; } urn = unescape(urn); try { mediator = (yield Mediator.findOne({ urn: urn }).exec()); if (mediator == null) { this.status = 404; return; } heartbeat = this.request.body; if ((heartbeat != null ? heartbeat.uptime : void 0) == null) { this.status = 400; return; } if (mediator._configModifiedTS > mediator._lastHeartbeat || (heartbeat != null ? heartbeat.config : void 0) === true) { this.body = mediator.config; } else { this.body = ""; } if (heartbeat != null) { update = { _lastHeartbeat: new Date(), _uptime: heartbeat.uptime }; (yield Mediator.findByIdAndUpdate(mediator._id, update).exec()); } return this.status = 200; } catch (error) { err = error; return utils.logAndSetResponse(this, 500, "Could not process mediator heartbeat (urn: " + urn + "): " + err, 'error'); } }; validateConfigField = function(param, def, field) { var k, paramField, results, results1, templateFields, v; switch (def.type) { case 'string': if (typeof field !== 'string') { throw constructError("Expected config param " + param + " to be a string.", 'ValidationError'); } break; case 'bigstring': if (typeof field !== 'string') { throw constructError("Expected config param " + param + " to be a large string.", 'ValidationError'); } break; case 'number': if (typeof field !== 'number') { throw constructError("Expected config param " + param + " to be a number.", 'ValidationError'); } break; case 'bool': if (typeof field !== 'boolean') { throw constructError("Expected config param " + param + " to be a boolean.", 'ValidationError'); } break; case 'option': if ((def.values.indexOf(field)) === -1) { throw constructError("Expected config param " + param + " to be one of " + def.values, 'ValidationError'); } break; case 'map': if (typeof field !== 'object') { throw constructError("Expected config param " + param + " to be an object.", 'ValidationError'); } results = []; for (k in field) { v = field[k]; if (typeof v !== 'string') { throw constructError("Expected config param " + param + " to only contain string values.", 'ValidationError'); } else { results.push(void 0); } } return results; break; case 'struct': if (typeof field !== 'object') { throw constructError("Expected config param " + param + " to be an object.", 'ValidationError'); } templateFields = def.template.map(function(tp) { return tp.param; }); results1 = []; for (paramField in field) { if (indexOf.call(templateFields, paramField) < 0) { throw constructError("Field " + paramField + " is not defined in template definition for config param " + param + ".", 'ValidationError'); } else { results1.push(void 0); } } return results1; break; case 'password': if (typeof field !== 'string') { throw constructError("Expected config param " + param + " to be a string representing a password.", 'ValidationError'); } } }; validateConfig = function(configDef, config) { return Object.keys(config).every(function(param) { var matchingDefs; matchingDefs = configDef.filter(function(def) { return def.param === param; }); if (matchingDefs.length === 0) { throw constructError("No config definition found for parameter " + param, 'ValidationError'); } return matchingDefs.map(function(def) { var field, i, j, len, ref, results; if (def.array) { if (!utils.typeIsArray(config[param])) { throw constructError("Expected config param " + param + " to be an array of type " + def.type, 'ValidationError'); } ref = config[param]; results = []; for (i = j = 0, len = ref.length; j < len; i = ++j) { field = ref[i]; results.push(validateConfigField(param + "[" + i + "]", def, field)); } return results; } else { return validateConfigField(param, def, config[param]); } }); }); }; if (process.env.NODE_ENV === "test") { exports.validateConfig = validateConfig; } exports.setConfig = function*(urn) { var config, err, error, error1, mediator; if (!authorisation.inGroup('admin', this.authenticated)) { utils.logAndSetResponse(this, 403, "User " + this.authenticated.email + " is not an admin, API access to removeMediator denied.", 'info'); return; } urn = unescape(urn); config = this.request.body; try { mediator = (yield Mediator.findOne({ urn: urn }).exec()); if (mediator == null) { this.status = 404; this.body = 'No mediator found for this urn.'; return; } try { restoreMaskedPasswords(mediator.configDefs, config, mediator.config); validateConfig(mediator.configDefs, config); } catch (error) { err = error; this.status = 400; this.body = err.message; return; } (yield Mediator.findOneAndUpdate({ urn: urn }, { config: this.request.body, _configModifiedTS: new Date() }).exec()); return this.status = 200; } catch (error1) { err = error1; return utils.logAndSetResponse(this, 500, "Could not set mediator config (urn: " + urn + "): " + err, 'error'); } }; saveDefaultChannelConfig = function(channels) { var channel, j, l, len, len1, promises, ref, route; promises = []; for (j = 0, len = channels.length; j < len; j++) { channel = channels[j]; delete channel._id; ref = channel.routes; for (l = 0, len1 = ref.length; l < len1; l++) { route = ref[l]; delete route._id; } promises.push(new Channel(channel).save()); } return promises; }; exports.loadDefaultChannels = function*(urn) { var channels, err, error, filteredChannelConfig, mediator; if (!authorisation.inGroup('admin', this.authenticated)) { utils.logAndSetResponse(this, 403, "User " + this.authenticated.email + " is not an admin, API access to removeMediator denied.", 'info'); return; } urn = unescape(urn); channels = this.request.body; try { mediator = (yield Mediator.findOne({ urn: urn }).lean().exec()); if (mediator == null) { this.status = 404; this.body = 'No mediator found for this urn.'; return; } if ((channels == null) || channels.length === 0) { (yield Q.all(saveDefaultChannelConfig(mediator.defaultChannelConfig))); } else { filteredChannelConfig = mediator.defaultChannelConfig.filter(function(channel) { var ref; return ref = channel.name, indexOf.call(channels, ref) >= 0; }); if (filteredChannelConfig.length < channels.length) { utils.logAndSetResponse(this, 400, "Could not load mediator default channel config, one or more channels in the request body not found in the mediator config (urn: " + urn + ")", 'error'); return; } else { (yield Q.all(saveDefaultChannelConfig(filteredChannelConfig))); } } return this.status = 201; } catch (error) { err = error; logger.debug(err.stack); return utils.logAndSetResponse(this, 500, "Could not load mediator default channel config (urn: " + urn + "): " + err, 'error'); } }; //# sourceMappingURL=mediators.js.map