openhim-core
Version:
The OpenHIM core application that provides logging and routing of http requests
262 lines (203 loc) • 8.69 kB
text/coffeescript
User = require('../model/users').User
Q = require 'q'
logger = require 'winston'
authorisation = require './authorisation'
moment = require 'moment'
randtoken = require 'rand-token'
contact = require '../contact'
config = require "../config/config"
config.newUserExpiry = config.get('newUserExpiry')
utils = require "../utils"
###
# Get authentication details
###
exports.authenticate = (email) ->
email = unescape email
try
user = yield User.findOne(email: email).exec()
if not user
utils.logAndSetResponse this, 404, "Could not find user by email #{email}", 'info'
else
this.body =
salt: user.passwordSalt
ts: new Date()
catch e
utils.logAndSetResponse this, 500, "Error during authentication #{e}", 'error'
#######################################
### New User Set Password Functions ###
#######################################
# get the new user details
exports.getNewUser = (token) ->
token = unescape token
try
projectionRestriction = "firstname": 1, "surname": 1, "msisdn": 1, "token": 1, "locked": 1, "expiry": 1, "_id": 0
result = yield User.findOne(token: token, projectionRestriction).exec()
if not result
this.body = "User with token #{token} could not be found."
this.status = 404
else
# if expiry date has past
if moment(result.expiry).utc().format() < moment().utc().format()
# new user- set password - expired
this.body = "User with token #{token} has expired to set their password."
this.status = 410
else
# valid new user - set password
this.body = result
catch e
utils.logAndSetResponse this, 500, "Could not find user with token #{token} via the API #{e}", 'error'
# update the password/details for the new user
exports.updateNewUser = (token) ->
token = unescape token
userData = this.request.body
try
# first try get new user details to check expiry date
newUserOldData = yield User.findOne(token: token).exec()
if not newUserOldData
this.body = "User with token #{token} could not be found."
this.status = 404
return
else
# if expiry date has past
if moment(newUserOldData.expiry).utc().format() < moment().utc().format()
# new user- set password - expired
this.body = "User with token #{token} has expired to set their password."
this.status = 410
return
catch e
utils.logAndSetResponse this, 500, "Could not find user with token #{token} via the API #{e}", 'error'
return
# check to make sure 'msisdn' isnt 'undefined' when saving
if userData.msisdn then msisdn = userData.msisdn else msisdn = null
# construct user object to prevent other properties from being updated
newUserUpdate =
firstname: userData.firstname
surname: userData.surname
token: null
locked: false
expiry: null
msisdn: msisdn
passwordAlgorithm: userData.passwordAlgorithm
passwordSalt: userData.passwordSalt
passwordHash: userData.passwordHash
try
yield User.findOneAndUpdate(token: token, newUserUpdate).exec()
this.body = "Successfully set new user password."
logger.info "New user updated by token #{token}"
catch e
utils.logAndSetResponse this, 500, "Could not update user with token #{token} via the API #{e}", 'error'
#######################################
### New User Set Password Functions ###
#######################################
plainMessageTemplate = (firstname, setPasswordLink) -> """
<---------- New User - Set Password ---------->
Hi #{firstname},
A profile has been created for you on OpenHIM
Follow the below link to set your password and log into OpenHIM Console
#{setPasswordLink}
<---------- New User - Set Password ---------->
"""
htmlMessageTemplate = (firstname, setPasswordLink) -> """
<h1>New OpenHIM Profile</h1>
<p>Hi #{firstname},<br/><br/>A profile has been created for you on OpenHIM</p>
<p>Follow the below link to set your password and log into OpenHIM Console</p>
<p>#{setPasswordLink}</p>
"""
###
# Adds a user
###
exports.addUser = ->
# Test if the user is authorised
if not authorisation.inGroup 'admin', this.authenticated
utils.logAndSetResponse this, 403, "User #{this.authenticated.email} is not an admin, API access to addUser denied.", 'info'
return
userData = this.request.body
# Generate the new user token here
# set locked = true
# set expiry date = true
token = randtoken.generate 32
userData.token = token
userData.locked = true
duration = config.newUserExpiry.duration
durationType = config.newUserExpiry.durationType
userData.expiry = moment().add(duration, durationType).utc().format()
consoleURL = config.alerts.consoleURL
setPasswordLink = "#{consoleURL}/#/set-password/#{token}"
try
user = new User userData
result = yield Q.ninvoke user, 'save'
# Send email to new user to set password
plainMessage = plainMessageTemplate userData.firstname, setPasswordLink
htmlMessage = htmlMessageTemplate userData.firstname, setPasswordLink
contact.contactUser 'email', userData.email, 'OpenHIM Console Profile', plainMessage, htmlMessage, ->
logger.info 'The email has been sent to the new user'
this.body = 'User successfully created'
this.status = 201
logger.info "User #{this.authenticated.email} created user #{userData.email}"
catch e
utils.logAndSetResponse this, 500, "Could not add user via the API #{e}", 'error'
###
# Retrieves the details of a specific user
###
exports.getUser = (email) ->
email = unescape email
# Test if the user is authorised, allow a user to fetch their own details
if not authorisation.inGroup('admin', this.authenticated) and this.authenticated.email isnt email
utils.logAndSetResponse this, 403, "User #{this.authenticated.email} is not an admin, API access to getUser denied.", 'info'
return
try
result = yield User.findOne(email: email).exec()
if not result
this.body = "User with email #{email} could not be found."
this.status = 404
else
this.body = result
catch e
utils.logAndSetResponse this, 500, "Could not get user via the API #{e}", 'error'
exports.updateUser = (email) ->
email = unescape email
# Test if the user is authorised, allow a user to update their own details
if not authorisation.inGroup('admin', this.authenticated) and this.authenticated.email isnt email
utils.logAndSetResponse this, 403, "User #{this.authenticated.email} is not an admin, API access to updateUser denied.", 'info'
return
userData = this.request.body
# reset token/locked/expiry when user is updated and password supplied
if userData.passwordAlgorithm and userData.passwordHash and userData.passwordSalt
userData.token = null
userData.locked = false
userData.expiry = null
# Don't allow a non-admin user to change their groups
if this.authenticated.email is email and not authorisation.inGroup 'admin', this.authenticated then delete userData.groups
#Ignore _id if it exists (update is by email)
if userData._id then delete userData._id
try
yield User.findOneAndUpdate(email: email, userData).exec()
this.body = "Successfully updated user."
logger.info "User #{this.authenticated.email} updated user #{userData.email}"
catch e
utils.logAndSetResponse this, 500, "Could not update user #{email} via the API #{e}", 'error'
exports.removeUser = (email) ->
# Test if the user is authorised
if not authorisation.inGroup 'admin', this.authenticated
utils.logAndSetResponse this, 403, "User #{this.authenticated.email} is not an admin, API access to removeUser denied.", 'info'
return
email = unescape email
# Test if the user is root@openhim.org
if email is 'root@openhim.org'
utils.logAndSetResponse this, 403, "User #{this.authenticated.email} is OpenHIM root, User cannot be deleted through the API", 'info'
return
try
yield User.findOneAndRemove(email: email).exec()
this.body = "Successfully removed user with email #{email}"
logger.info "User #{this.authenticated.email} removed user #{email}"
catch e
utils.logAndSetResponse this, 500, "Could not remove user #{email} via the API #{e}", 'error'
exports.getUsers = ->
# Test if the user is authorised
if not authorisation.inGroup 'admin', this.authenticated
utils.logAndSetResponse this, 403, "User #{this.authenticated.email} is not an admin, API access to getUsers denied.", 'info'
return
try
this.body = yield User.find().exec()
catch e
utils.logAndSetResponse this, 500, "Could not fetch all users via the API #{e}", 'error'