UNPKG

openhim-core

Version:

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

265 lines (218 loc) 9.51 kB
Channel = require('../model/channels').Channel Client = require('../model/clients').Client logger = require 'winston' authorisation = require './authorisation' utils = require '../utils' ### # Roles is a virtual API; virtual in the sense that it is not linked # to a concrete roles collection. # # Rather it an abstraction of the 'allow' field on Channels and 'roles' on Clients, # providing a mechanism for setting up allowed permissions. ### filterRolesFromChannels = (channels, clients) -> rolesMap = {} # K: permission, V: channels, clients that share permission for ch in channels for permission in ch.allow isClient = false for cl in clients if cl.clientID is permission isClient = true if not isClient if not rolesMap[permission] rolesMap[permission] = channels: [] clients: [] rolesMap[permission].channels.push _id: ch._id, name: ch.name for cl in clients for permission in cl.roles if not rolesMap[permission] rolesMap[permission] = channels: [] clients: [] rolesMap[permission].clients.push _id: cl._id, clientID: cl.clientID rolesArray = [] for role of rolesMap rolesArray.push name: role channels: rolesMap[role].channels clients: rolesMap[role].clients return rolesArray exports.getRoles = -> # Test if the user is authorised if not authorisation.inGroup 'admin', this.authenticated return utils.logAndSetResponse this, 403, "User #{this.authenticated.email} is not an admin, API access to getRoles denied.", 'info' try channels = yield Channel.find({}, {name: 1, allow: 1 }).exec() clients = yield Client.find({}, {clientID: 1, roles: 1 }).exec() this.body = filterRolesFromChannels channels, clients catch e logger.error "Could not fetch roles via the API: #{e.message}" this.message = e.message this.status = 500 exports.getRole = (name) -> # Test if the user is authorised if not authorisation.inGroup 'admin', this.authenticated return utils.logAndSetResponse this, 403, "User #{this.authenticated.email} is not an admin, API access to getRole denied.", 'info' try channels = yield Channel.find({allow: {$in: [name]}}, {name: 1 }).exec() clients = yield Client.find({ roles: $in: [name]}, {clientID: 1 }).exec() if (channels is null or channels.length is 0) and (clients is null or clients.length is 0) utils.logAndSetResponse this, 404, "Role with name '#{name}' could not be found.", 'info' else this.body = name: name channels: channels.map (r) -> _id: r._id, name: r.name clients: clients.map (c) -> _id: c._id, clientID: c.clientID catch e logger.error "Could not find role with name '#{name}' via the API: #{e.message}" this.body = e.message this.status = 500 buildFindChannelByIdOrNameCriteria = (ctx, role) -> criteria = {} ids = [] names = [] for ch in role.channels if ch._id ids.push ch._id else if ch.name names.push ch.name else utils.logAndSetResponse ctx, 400, "_id and/or name must be specified for a channel", 'info' return null if ids.length > 0 and names.length > 0 criteria = $or: [ _id: $in: ids , name: $in: names ] else if ids.length > 0 criteria._id = $in: ids if names.length > 0 criteria.name = $in: names return criteria buildFindClientByIdOrClientIDCriteria = (ctx, role) -> criteria = {} ids = [] clientIDs = [] for ch in role.clients if ch._id ids.push ch._id else if ch.clientID clientIDs.push ch.clientID else utils.logAndSetResponse ctx, 400, "_id and/or clientID must be specified for a client", 'info' return null if ids.length > 0 and clientIDs.length > 0 criteria = $or: [ _id: $in: ids , clientID: $in: clientIDs ] else if ids.length > 0 criteria._id = $in: ids if clientIDs.length > 0 criteria.clientID = $in: clientIDs return criteria exports.addRole = -> # Test if the user is authorised if not authorisation.inGroup 'admin', this.authenticated return utils.logAndSetResponse this, 403, "User #{this.authenticated.email} is not an admin, API access to addRole denied.", 'info' role = this.request.body if not role.name return utils.logAndSetResponse this, 400, 'Must specify a role name', 'info' if role.channels?.length is 0 and role.clients?.length is 0 return utils.logAndSetResponse this, 400, 'Must specify at least one channel or client to link the role to', 'info' try chResult = yield Channel.find({allow: {$in: [role.name]}}, {name: 1 }).exec() clResult = yield Client.find({roles: {$in: [role.name]}}, {clientID: 1 }).exec() if chResult?.length > 0 or clResults?.length > 0 return utils.logAndSetResponse this, 400, "Role with name '#{role.name}' already exists.", 'info' if role.channels chCriteria = buildFindChannelByIdOrNameCriteria this, role return if not chCriteria if role.clients clCriteria = buildFindClientByIdOrClientIDCriteria this, role return if not clCriteria if role.channels yield Channel.update(chCriteria, { $push: allow: role.name }, { multi: true }).exec() if role.clients yield Client.update(clCriteria, { $push: roles: role.name }, { multi: true }).exec() logger.info "User #{this.authenticated.email} setup role '#{role.name}'" this.body = 'Role successfully created' this.status = 201 catch e logger.error "Could not add a role via the API: #{e.message}" this.body = e.message this.status = 400 exports.updateRole = (name) -> # Test if the user is authorised if not authorisation.inGroup 'admin', this.authenticated return utils.logAndSetResponse this, 403, "User #{this.authenticated.email} is not an admin, API access to updateRole denied.", 'info' role = this.request.body try # request validity checks chResult = yield Channel.find({allow: {$in: [name]}}, {name: 1 }).exec() clResult = yield Client.find({roles: {$in: [name]}}, {clientID: 1 }).exec() if (chResult is null or chResult.length is 0) and (clResult is null or clResult.length is 0) return utils.logAndSetResponse this, 404, "Role with name '#{name}' could not be found.", 'info' if role.name # do check here but only perform rename updates later after channel/client updates channels = yield Channel.find({allow: {$in: [role.name]}}, {name: 1 }).exec() clients = yield Client.find({roles: {$in: [role.name]}}, {name: 1 }).exec() if channels?.length > 0 or clients?.length > 0 return utils.logAndSetResponse this, 400, "Role with name '#{role.name}' already exists.", 'info' if role.channels chCriteria = buildFindChannelByIdOrNameCriteria this, role return if not chCriteria if role.clients clCriteria = buildFindClientByIdOrClientIDCriteria this, role return if not clCriteria # update channels if role.channels # clear role from existing yield Channel.update({}, { $pull: allow: name }, { multi: true }).exec() # set role on channels if role.channels.length > 0 yield Channel.update(chCriteria, { $push: allow: name }, { multi: true }).exec() # update clients if role.clients # clear role from existing yield Client.update({}, { $pull: roles: name }, { multi: true }).exec() # set role on clients if role.clients?.length > 0 yield Client.update(clCriteria, { $push: roles: name }, { multi: true }).exec() # rename role if role.name yield Channel.update({ allow: $in: [name] }, { $push: allow: role.name }, { multi: true }).exec() yield Channel.update({ allow: $in: [name] }, { $pull: allow: name }, { multi: true }).exec() yield Client.update({ roles: $in: [name] }, { $push: roles: role.name }, { multi: true }).exec() yield Client.update({ roles: $in: [name] }, { $pull: roles: name }, { multi: true }).exec() logger.info "User #{this.authenticated.email} updated role with name '#{name}'" this.body = 'Successfully updated role' this.status = 200 catch e logger.error "Could not update role with name '#{name}' via the API: #{e.message}" this.body = e.message this.status = 500 exports.deleteRole = (name) -> # Test if the user is authorised if not authorisation.inGroup 'admin', this.authenticated return utils.logAndSetResponse this, 403, "User #{this.authenticated.email} is not an admin, API access to updateRole denied.", 'info' try channels = yield Channel.find({allow: {$in: [name]}}, {name: 1 }).exec() clients = yield Client.find({ roles: $in: [name]}, {clientID: 1 }).exec() if (channels is null or channels.length is 0) and (clients is null or clients.length is 0) return utils.logAndSetResponse this, 404, "Role with name '#{name}' could not be found.", 'info' yield Channel.update({}, { $pull: allow: name }, { multi: true }).exec() yield Client.update({}, { $pull: roles: name }, { multi: true }).exec() logger.info "User #{this.authenticated.email} deleted role with name '#{name}'" this.body = 'Successfully deleted role' catch e logger.error "Could not update role with name '#{name}' via the API: #{e.message}" this.body = e.message this.status = 500