2015-07-20 00:09:47 -07:00
'use strict' ;
exports = module . exports = {
2016-04-17 18:27:11 +02:00
get : get ,
2015-07-20 00:09:47 -07:00
update : update ,
2016-04-17 18:27:11 +02:00
list : list ,
create : create ,
remove : remove ,
2015-07-20 00:09:47 -07:00
verifyPassword : verifyPassword ,
2016-01-18 15:37:03 +01:00
requireAdmin : requireAdmin ,
2016-02-09 15:47:02 -08:00
sendInvite : sendInvite ,
2016-09-21 15:34:58 -07:00
setGroups : setGroups ,
setAliases : setAliases ,
getAliases : getAliases
2015-07-20 00:09:47 -07:00
} ;
var assert = require ( 'assert' ) ,
2016-06-03 11:10:59 +02:00
clients = require ( '../clients.js' ) ,
2016-09-20 15:07:11 -07:00
constants = require ( '../constants.js' ) ,
2016-01-20 15:33:11 +01:00
generatePassword = require ( '../password.js' ) . generate ,
2015-07-20 00:09:47 -07:00
HttpError = require ( 'connect-lastmile' ) . HttpError ,
HttpSuccess = require ( 'connect-lastmile' ) . HttpSuccess ,
2016-06-03 10:17:52 +02:00
oauth2 = require ( './oauth2.js' ) ,
2015-07-20 00:09:47 -07:00
user = require ( '../user.js' ) ,
2016-06-03 00:04:17 -07:00
UserError = user . UserError ,
2016-09-21 15:34:58 -07:00
util = require ( 'util' ) ,
2016-06-03 00:04:17 -07:00
_ = require ( 'underscore' ) ;
2015-07-20 00:09:47 -07:00
2016-05-01 20:01:34 -07:00
function auditSource ( req ) {
var ip = req . headers [ 'x-forwarded-for' ] || req . connection . remoteAddress || null ;
return { ip : ip , username : req . user ? req . user . username : null , userId : req . user ? req . user . id : null } ;
}
2016-04-17 18:27:11 +02:00
function create ( req , res , next ) {
2015-07-20 00:09:47 -07:00
assert . strictEqual ( typeof req . body , 'object' ) ;
if ( typeof req . body . email !== 'string' ) return next ( new HttpError ( 400 , 'email must be string' ) ) ;
2016-01-18 16:53:51 +01:00
if ( typeof req . body . invite !== 'boolean' ) return next ( new HttpError ( 400 , 'invite must be boolean' ) ) ;
2016-04-01 16:48:50 +02:00
if ( 'username' in req . body && typeof req . body . username !== 'string' ) return next ( new HttpError ( 400 , 'username must be string' ) ) ;
2016-01-20 00:05:06 -08:00
if ( 'displayName' in req . body && typeof req . body . displayName !== 'string' ) return next ( new HttpError ( 400 , 'displayName must be string' ) ) ;
2015-07-20 00:09:47 -07:00
2016-01-20 15:33:11 +01:00
var password = generatePassword ( ) ;
2015-07-20 00:09:47 -07:00
var email = req . body . email ;
2016-01-18 16:53:51 +01:00
var sendInvite = req . body . invite ;
2017-02-02 00:23:11 -08:00
var username = 'username' in req . body ? req . body . username : null ;
2016-01-19 23:34:49 -08:00
var displayName = req . body . displayName || '' ;
2015-07-20 00:09:47 -07:00
2016-05-01 20:01:34 -07:00
user . create ( username , password , email , displayName , auditSource ( req ) , { invitor : req . user , sendInvite : sendInvite } , function ( error , user ) {
2015-07-20 00:09:47 -07:00
if ( error && error . reason === UserError . BAD _FIELD ) return next ( new HttpError ( 400 , error . message ) ) ;
2016-06-02 15:41:07 +02:00
if ( error && error . reason === UserError . ALREADY _EXISTS ) return next ( new HttpError ( 409 , error . message ) ) ;
2015-07-20 00:09:47 -07:00
if ( error ) return next ( new HttpError ( 500 , error ) ) ;
var userInfo = {
id : user . id ,
username : user . username ,
2016-04-01 16:48:50 +02:00
displayName : user . displayName ,
2015-07-20 00:09:47 -07:00
email : user . email ,
2016-09-28 11:08:11 +02:00
alternateEmail : user . alternateEmail ,
2015-07-20 00:09:47 -07:00
admin : user . admin ,
2016-05-31 11:49:59 -07:00
groupIds : [ ] ,
2015-07-20 00:09:47 -07:00
resetToken : user . resetToken
} ;
2016-04-06 10:20:32 -07:00
next ( new HttpSuccess ( 201 , userInfo ) ) ;
2015-07-20 00:09:47 -07:00
} ) ;
}
function update ( req , res , next ) {
2016-01-25 14:58:02 +01:00
assert . strictEqual ( typeof req . params . userId , 'string' ) ;
2015-07-20 00:09:47 -07:00
assert . strictEqual ( typeof req . user , 'object' ) ;
assert . strictEqual ( typeof req . body , 'object' ) ;
2016-01-25 14:12:09 +01:00
if ( 'email' in req . body && typeof req . body . email !== 'string' ) return next ( new HttpError ( 400 , 'email must be string' ) ) ;
2016-01-25 14:08:11 +01:00
if ( 'displayName' in req . body && typeof req . body . displayName !== 'string' ) return next ( new HttpError ( 400 , 'displayName must be string' ) ) ;
2016-06-02 23:53:06 -07:00
if ( 'username' in req . body && typeof req . body . username !== 'string' ) return next ( new HttpError ( 400 , 'username must be a string' ) ) ;
2015-07-20 00:09:47 -07:00
2016-02-25 14:03:42 +01:00
if ( req . user . id !== req . params . userId && ! req . user . admin ) return next ( new HttpError ( 403 , 'Not allowed' ) ) ;
2015-07-20 00:09:47 -07:00
2016-06-02 23:53:06 -07:00
user . update ( req . params . userId , req . body , auditSource ( req ) , function ( error ) {
if ( error && error . reason === UserError . BAD _FIELD ) return next ( new HttpError ( 400 , error . message ) ) ;
if ( error && error . reason === UserError . ALREADY _EXISTS ) return next ( new HttpError ( 409 , error . message ) ) ;
if ( error && error . reason === UserError . NOT _FOUND ) return next ( new HttpError ( 404 , 'User not found' ) ) ;
2015-07-20 00:09:47 -07:00
if ( error ) return next ( new HttpError ( 500 , error ) ) ;
2016-06-02 23:53:06 -07:00
next ( new HttpSuccess ( 204 ) ) ;
2015-07-20 00:09:47 -07:00
} ) ;
}
2016-04-17 18:27:11 +02:00
function list ( req , res , next ) {
2016-06-03 00:04:17 -07:00
user . list ( function ( error , results ) {
2015-07-20 00:09:47 -07:00
if ( error ) return next ( new HttpError ( 500 , error ) ) ;
2016-06-03 00:04:17 -07:00
var users = results . map ( function ( result ) {
2016-09-28 11:08:11 +02:00
return _ . pick ( result , 'id' , 'username' , 'email' , 'alternateEmail' , 'displayName' , 'groupIds' , 'admin' ) ;
2016-06-03 00:04:17 -07:00
} ) ;
next ( new HttpSuccess ( 200 , { users : users } ) ) ;
2015-07-20 00:09:47 -07:00
} ) ;
}
2016-04-17 18:27:11 +02:00
function get ( req , res , next ) {
2015-07-20 00:09:47 -07:00
assert . strictEqual ( typeof req . params . userId , 'string' ) ;
2016-02-25 14:03:42 +01:00
assert . strictEqual ( typeof req . user , 'object' ) ;
2015-07-20 00:09:47 -07:00
2016-02-25 13:44:53 +01:00
if ( req . user . id !== req . params . userId && ! req . user . admin ) return next ( new HttpError ( 403 , 'Not allowed' ) ) ;
2015-07-20 00:09:47 -07:00
user . get ( req . params . userId , function ( error , result ) {
if ( error && error . reason === UserError . NOT _FOUND ) return next ( new HttpError ( 404 , 'No such user' ) ) ;
if ( error ) return next ( new HttpError ( 500 , error ) ) ;
2016-06-03 00:00:11 -07:00
next ( new HttpSuccess ( 200 , {
id : result . id ,
username : result . username ,
displayName : result . displayName ,
email : result . email ,
2016-09-28 11:08:11 +02:00
alternateEmail : result . alternateEmail ,
2016-06-03 00:00:11 -07:00
admin : result . admin ,
groupIds : result . groupIds
} ) ) ;
2015-07-20 00:09:47 -07:00
} ) ;
}
2016-04-17 18:27:11 +02:00
function remove ( req , res , next ) {
2015-07-20 00:09:47 -07:00
assert . strictEqual ( typeof req . params . userId , 'string' ) ;
// rules:
// - admin can remove any user
// - admin cannot remove admin
// - user cannot remove himself <- TODO should this actually work?
if ( req . user . id === req . params . userId ) return next ( new HttpError ( 403 , 'Not allowed to remove yourself.' ) ) ;
2016-06-02 22:25:48 -07:00
user . remove ( req . params . userId , auditSource ( req ) , function ( error ) {
2016-08-31 21:20:48 -07:00
if ( error && error . reason === UserError . BAD _FIELD ) return next ( new HttpError ( 400 , error . message ) ) ;
2016-04-03 01:41:47 +02:00
if ( error && error . reason === UserError . NOT _FOUND ) return next ( new HttpError ( 404 , 'No such user' ) ) ;
2015-07-20 00:09:47 -07:00
if ( error ) return next ( new HttpError ( 500 , error ) ) ;
2016-06-02 22:25:48 -07:00
next ( new HttpSuccess ( 204 ) ) ;
2015-07-20 00:09:47 -07:00
} ) ;
}
function verifyPassword ( req , res , next ) {
assert . strictEqual ( typeof req . body , 'object' ) ;
2016-06-03 10:17:52 +02:00
// using an 'sdk' token we skip password checks
2016-06-03 11:10:59 +02:00
var error = oauth2 . validateRequestedScopes ( req , [ clients . SCOPE _ROLE _SDK ] ) ;
2016-06-03 10:17:52 +02:00
if ( ! error ) return next ( ) ;
2015-07-20 00:09:47 -07:00
if ( typeof req . body . password !== 'string' ) return next ( new HttpError ( 400 , 'API call requires user password' ) ) ;
2016-04-17 19:17:01 +02:00
user . verifyWithUsername ( req . user . username , req . body . password , function ( error ) {
if ( error && error . reason === UserError . WRONG _PASSWORD ) return next ( new HttpError ( 403 , 'Password incorrect' ) ) ;
if ( error && error . reason === UserError . NOT _FOUND ) return next ( new HttpError ( 403 , 'Password incorrect' ) ) ;
2015-07-20 00:09:47 -07:00
if ( error ) return next ( new HttpError ( 500 , error ) ) ;
2017-05-05 15:36:47 -07:00
req . body . password = '<redacted>' ; // this will prevent logs from displaying plain text password
2016-04-17 19:17:01 +02:00
next ( ) ;
2015-07-20 00:09:47 -07:00
} ) ;
}
/ *
Middleware which makes the route only accessable for the admin user .
* /
function requireAdmin ( req , res , next ) {
assert . strictEqual ( typeof req . user , 'object' ) ;
2016-02-25 11:42:25 +01:00
if ( ! req . user . admin ) return next ( new HttpError ( 403 , 'API call requires admin rights.' ) ) ;
2016-02-09 09:37:12 -08:00
2016-02-25 11:42:25 +01:00
next ( ) ;
2015-07-20 00:09:47 -07:00
}
2016-01-18 15:37:03 +01:00
function sendInvite ( req , res , next ) {
assert . strictEqual ( typeof req . params . userId , 'string' ) ;
2016-10-13 15:57:58 -07:00
user . sendInvite ( req . params . userId , { invitor : req . user } , function ( error , result ) {
2016-01-18 15:37:03 +01:00
if ( error && error . reason === UserError . NOT _FOUND ) return next ( new HttpError ( 404 , 'User not found' ) ) ;
if ( error ) return next ( new HttpError ( 500 , error ) ) ;
2016-04-04 18:14:07 +02:00
next ( new HttpSuccess ( 200 , { resetToken : result } ) ) ;
2016-01-18 15:37:03 +01:00
} ) ;
}
2016-02-09 15:47:02 -08:00
function setGroups ( req , res , next ) {
assert . strictEqual ( typeof req . body , 'object' ) ;
assert . strictEqual ( typeof req . params . userId , 'string' ) ;
if ( ! Array . isArray ( req . body . groupIds ) ) return next ( new HttpError ( 400 , 'API call requires a groups array.' ) ) ;
2016-02-11 11:29:04 +01:00
// this route is only allowed for admins, so req.user has to be an admin
2016-09-20 15:07:11 -07:00
if ( req . user . id === req . params . userId && req . body . groupIds . indexOf ( constants . ADMIN _GROUP _ID ) === - 1 ) return next ( new HttpError ( 403 , 'Admin removing itself from admins is not allowed' ) ) ;
2016-02-11 11:29:04 +01:00
2016-02-09 15:47:02 -08:00
user . setGroups ( req . params . userId , req . body . groupIds , function ( error ) {
if ( error && error . reason === UserError . NOT _FOUND ) return next ( new HttpError ( 404 , 'One or more groups not found' ) ) ;
if ( error ) return next ( new HttpError ( 500 , error ) ) ;
next ( new HttpSuccess ( 204 ) ) ;
} ) ;
}
2016-09-21 15:34:58 -07:00
function setAliases ( req , res , next ) {
assert . strictEqual ( typeof req . params . userId , 'string' ) ;
if ( ! util . isArray ( req . body . aliases ) ) return next ( new HttpError ( 400 , 'aliases must be an array' ) ) ;
for ( var i = 0 ; i < req . body . aliases . length ; i ++ ) {
if ( typeof req . body . aliases [ i ] !== 'string' ) return next ( new HttpError ( 400 , 'alias must be a string' ) ) ;
}
user . setAliases ( req . params . userId , req . body . aliases , function ( error ) {
if ( error && error . reason === UserError . NOT _FOUND ) return next ( new HttpError ( 404 , 'No such user' ) ) ;
if ( error && error . reason === UserError . BAD _FIELD ) return next ( new HttpError ( 400 , error . message ) ) ;
if ( error && error . reason === UserError . ALREADY _EXISTS ) return next ( new HttpError ( 409 , 'One or more aliases already exist' ) ) ;
if ( error ) return next ( new HttpError ( 500 , error ) ) ;
next ( new HttpSuccess ( 200 ) ) ;
} ) ;
}
function getAliases ( req , res , next ) {
assert . strictEqual ( typeof req . params . userId , 'string' ) ;
user . getAliases ( req . params . userId , function ( error , aliases ) {
if ( error && error . reason === UserError . NOT _FOUND ) return next ( new HttpError ( 404 , 'No such user' ) ) ;
if ( error ) return next ( new HttpError ( 500 , error ) ) ;
next ( new HttpSuccess ( 200 , { aliases : aliases } ) ) ;
} ) ;
}