openhim-core
Version:
The OpenHIM core application that provides logging and routing of http requests
472 lines (444 loc) • 16.3 kB
JavaScript
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