2020-04-22 17:24:15 +02:00
import express from 'express' ;
import mongoose from 'mongoose' ;
import bcrypt from 'bcryptjs' ;
import UserValidate from './validate/user' ;
import UserModel from '../models/user' ;
2020-04-23 17:46:00 +02:00
import mail from '../helpers/mail' ;
2020-04-22 17:24:15 +02:00
const router = express . Router ( ) ;
router . get ( '/users' , ( req , res ) = > {
2020-04-24 12:25:32 +02:00
if ( ! req . auth ( res , [ 'admin' ] , 'basic' ) ) return ;
UserModel . find ( { } ) . lean ( ) . exec ( ( err , data :any ) = > {
res . json ( data . map ( e = > UserValidate . output ( e ) ) . filter ( e = > e !== null ) ) ; // validate all and filter null values from validation errors
} ) ;
} ) ;
2020-04-27 14:26:51 +02:00
router . get ( '/user:username([/](?!key|new).?*|/?)' , ( req , res , next ) = > { // this path matches /user, /user/ and /user/xxx, but not /user/key or user/new. See https://forbeslindesay.github.io/express-route-tester/ for the generated regex
req . params . username = req . params [ 0 ] ;
2020-04-24 12:25:32 +02:00
if ( ! req . auth ( res , [ 'read' , 'write' , 'maintain' , 'dev' , 'admin' ] , 'basic' ) ) return ;
let username = req . authDetails . username ;
if ( req . params . username !== undefined ) {
if ( ! req . auth ( res , [ 'admin' ] , 'basic' ) ) return ;
username = req . params . username ;
}
UserModel . findOne ( { name : username } ) . lean ( ) . exec ( ( err , data :any ) = > {
2020-04-24 17:36:39 +02:00
if ( err ) next ( err ) ;
if ( data ) {
res . json ( UserValidate . output ( data ) ) ; // validate all and filter null values from validation errors
}
else {
res . status ( 404 ) . json ( { status : 'Not found' } ) ;
}
2020-04-24 12:25:32 +02:00
} ) ;
2020-04-22 17:24:15 +02:00
} ) ;
2020-04-27 14:26:51 +02:00
router . put ( '/user:username([/](?!key|new).?*|/?)' , ( req , res , next ) = > { // this path matches /user, /user/ and /user/xxx, but not /user/key or user/new
2020-04-27 15:10:14 +02:00
req . params . username = req . params [ 0 ] ;
2020-04-24 17:36:39 +02:00
if ( ! req . auth ( res , [ 'read' , 'write' , 'maintain' , 'dev' , 'admin' ] , 'basic' ) ) return ;
let username = req . authDetails . username ;
if ( req . params . username !== undefined ) {
if ( ! req . auth ( res , [ 'admin' ] , 'basic' ) ) return ;
username = req . params . username ;
}
const { error , value : user } = UserValidate . input ( req . body , 'change' + ( req . authDetails . level === 'admin' ? 'admin' : '' ) ) ;
if ( error !== undefined ) {
res . status ( 400 ) . json ( { status : 'Invalid body format' } ) ;
return ;
}
if ( user . hasOwnProperty ( 'pass' ) ) {
user . pass = bcrypt . hashSync ( user . pass , 10 ) ;
}
// check that user does not already exist if new name was specified
if ( user . hasOwnProperty ( 'name' ) && user . name !== username ) {
UserModel . find ( { name : user.name } ) . lean ( ) . exec ( ( err , data :any ) = > {
if ( err ) next ( err ) ;
2020-04-27 15:10:14 +02:00
if ( data . length > 0 || UserValidate . isSpecialName ( user . name ) ) {
2020-04-24 17:36:39 +02:00
res . status ( 400 ) . json ( { status : 'Username already taken' } ) ;
return ;
}
UserModel . findOneAndUpdate ( { name : username } , user , { new : true } ) . lean ( ) . exec ( ( err , data :any ) = > {
if ( err ) next ( err ) ;
if ( data ) {
res . json ( UserValidate . output ( data ) ) ; // validate all and filter null values from validation errors
}
else {
res . status ( 404 ) . json ( { status : 'Not found' } ) ;
}
} ) ;
} ) ;
}
else {
UserModel . findOneAndUpdate ( { name : username } , user , { new : true } ) . lean ( ) . exec ( ( err , data :any ) = > {
if ( err ) next ( err ) ;
if ( data ) {
res . json ( UserValidate . output ( data ) ) ; // validate all and filter null values from validation errors
}
else {
res . status ( 404 ) . json ( { status : 'Not found' } ) ;
}
} ) ;
}
} ) ;
2020-04-27 15:10:14 +02:00
router . delete ( '/user:username([/](?!key|new).?*|/?)' , ( req , res , next ) = > { // this path matches /user, /user/ and /user/xxx, but not /user/key or user/new. See https://forbeslindesay.github.io/express-route-tester/ for the generated regex
req . params . username = req . params [ 0 ] ;
if ( ! req . auth ( res , [ 'read' , 'write' , 'maintain' , 'dev' , 'admin' ] , 'basic' ) ) return ;
let username = req . authDetails . username ;
if ( req . params . username !== undefined ) {
if ( ! req . auth ( res , [ 'admin' ] , 'basic' ) ) return ;
username = req . params . username ;
}
UserModel . findOneAndDelete ( { name : username } ) . lean ( ) . exec ( ( err , data :any ) = > {
if ( err ) next ( err ) ;
if ( data ) {
res . json ( { status : 'OK' } )
}
else {
res . status ( 404 ) . json ( { status : 'Not found' } ) ;
}
} ) ;
} ) ;
2020-04-27 14:26:51 +02:00
router . get ( '/user/key' , ( req , res , next ) = > {
console . log ( 'hmm' ) ;
if ( ! req . auth ( res , [ 'read' , 'write' , 'maintain' , 'dev' , 'admin' ] , 'basic' ) ) return ;
UserModel . findOne ( { name : req.authDetails.username } ) . lean ( ) . exec ( ( err , data :any ) = > {
if ( err ) next ( err ) ;
res . json ( { key : data.key } ) ;
} ) ;
} ) ;
2020-04-22 17:24:15 +02:00
router . post ( '/user/new' , ( req , res , next ) = > {
2020-04-23 13:59:45 +02:00
if ( ! req . auth ( res , [ 'admin' ] , 'basic' ) ) return ;
2020-04-22 17:24:15 +02:00
// validate input
2020-04-24 17:36:39 +02:00
const { error , value : user } = UserValidate . input ( req . body , 'new' ) ;
2020-04-22 17:24:15 +02:00
if ( error !== undefined ) {
res . status ( 400 ) . json ( { status : 'Invalid body format' } ) ;
return ;
}
2020-04-22 17:38:24 +02:00
// check that user does not already exist
2020-04-24 12:25:32 +02:00
UserModel . find ( { name : user.name } ) . lean ( ) . exec ( ( err , data :any ) = > {
2020-04-22 17:38:24 +02:00
if ( err ) next ( err ) ;
2020-04-27 15:10:14 +02:00
if ( data . length > 0 || UserValidate . isSpecialName ( user . name ) ) {
2020-04-22 17:38:24 +02:00
res . status ( 400 ) . json ( { status : 'Username already taken' } ) ;
return ;
}
user . key = mongoose . Types . ObjectId ( ) ; // use object id as unique API key
bcrypt . hash ( user . pass , 10 , ( err , hash ) = > { // password hashing
user . pass = hash ;
new UserModel ( user ) . save ( ( err , data ) = > { // store user
if ( err ) next ( err ) ;
res . json ( UserValidate . output ( data . toObject ( ) ) ) ;
} ) ;
2020-04-22 17:24:15 +02:00
} ) ;
} ) ;
} ) ;
2020-04-23 17:46:00 +02:00
router . post ( '/user/passreset' , ( req , res , next ) = > {
// check if user/email combo exists
2020-04-24 10:53:45 +02:00
UserModel . find ( { name : req.body.name , email : req.body.email } ) . lean ( ) . exec ( ( err , data : any ) = > {
2020-04-23 17:46:00 +02:00
if ( err ) next ( err ) ;
if ( data . length === 1 ) { // it exists
const newPass = Math . random ( ) . toString ( 36 ) . substring ( 2 ) ;
bcrypt . hash ( newPass , 10 , ( err , hash ) = > { // password hashing
if ( err ) next ( err ) ;
2020-04-24 10:53:45 +02:00
UserModel . findByIdAndUpdate ( data [ 0 ] . _id , { pass : hash } , err = > { // write new password
2020-04-23 17:46:00 +02:00
if ( err ) next ( err ) ;
mail ( data [ 0 ] . email , 'Your new password for the DFOP database' , 'Hi, <br><br> You requested to reset your password.<br>Your new password is:<br><br>' + newPass + '<br><br>If you did not request a password reset, talk to the sysadmin quickly!<br><br>Have a nice day.<br><br>The DFOP team' , err = > {
if ( err ) next ( err ) ;
res . json ( { status : 'OK' } ) ;
} ) ;
} ) ;
} ) ;
}
else {
res . status ( 404 ) . json ( { status : 'Not found' } ) ;
}
} ) ;
} ) ;
2020-04-22 17:24:15 +02:00
module .exports = router ;