import { Response } from 'express' ; import { Body , Delete , Post , JsonController , Req , HttpError , UseBefore , BodyParam , ForbiddenError , InternalServerError , BadRequestError , OnUndefined , Res } from 'routing-controllers' ; import { json as bodyParserJson } from 'body-parser' ; import passportLoginMiddleware from '../security/passportLoginMiddleware' ; import emailService from '../services/EmailService' ; import { IUser } from '../../../shared/models/IUser' ; import { IUserModel , User } from '../models/User' ; import { JwtUtils } from '../security/JwtUtils' ; import * as errorCodes from '../config/errorCodes' ; import { Course } from '../models/Course' ; import config from '../config/main' ; @ JsonController ( '/auth' ) export class AuthController { api apiName apiGroup apiParam apiSuccess apiSuccessExample @ Post ( '/login' ) @ UseBefore ( bodyParserJson ( ) , passportLoginMiddleware ) postLogin ( @ Req ( ) request , @ Res ( ) response ) { const user = request . user ; response . cookie ( 'token' , JwtUtils . generateToken ( user ) , { httpOnly : true , sameSite : true , } ) ; response . json ( { user : user . toObject ( ) } ) ; return response ; } api apiName apiGroup apiSuccessExample @ Delete ( '/logout' ) logout ( @ Res ( ) response ) { response . clearCookie ( 'token' ) ; response . json ( { } ) ; return response ; } api apiName apiGroup apiParam apiError apiError apiError apiError apiError @ Post ( '/register' ) @ OnUndefined ( 204 ) async postRegister ( @ Body ( ) user ) { const existingUser = await User . findOne ( { $or : [ { email : user . email } , { uid : user . uid } ] } ) ; if ( existingUser ) { if ( user . role === 'student' && existingUser . uid === user . uid ) { throw new BadRequestError ( errorCodes . errorCodes . duplicateUid . code ) ; } if ( existingUser . email === user . email ) { throw new BadRequestError ( errorCodes . errorCodes . mail . duplicate . code ) ; } } if ( user . role !== 'teacher' && user . role !== 'student' ) { throw new BadRequestError ( 'You can only sign up as student or teacher' ) ; } if ( user . role === 'teacher' && ( typeof user . email !== 'string' || ! user . email . match ( config . teacherMailRegex ) ) ) { throw new BadRequestError ( errorCodes . errorCodes . mail . noTeacher . code ) ; } const newUser = new User ( user ) ; const savedUser = await newUser . save ( ) ; await this . addWhitelistedUserToCourses ( savedUser ) ; try { emailService . sendActivation ( savedUser ) ; } catch ( err ) { throw new InternalServerError ( errorCodes . errorCodes . mail . notSend . code ) ; } } api apiName apiGroup apiParam apiSuccess apiSuccessExample apiError @ Post ( '/activate' ) postActivation ( @ BodyParam ( 'authenticationToken' ) authenticationToken ) { return User . findOne ( { authenticationToken : authenticationToken } ) . then ( ( existingUser ) => { if ( ! existingUser ) { throw new HttpError ( 422 , 'could not activate user' ) ; } existingUser . authenticationToken = undefined ; existingUser . isActive = true ; return existingUser . save ( ) ; } ) . then ( ( user ) => { return { success : true } ; } ) ; } api apiName apiGroup apiParam apiParam apiParam apiError apiError apiError apiError apiError @ Post ( '/activationresend' ) @ OnUndefined ( 204 ) async activationResend ( @ BodyParam ( 'lastname' ) lastname , @ BodyParam ( 'uid' ) uid , @ BodyParam ( 'email' ) email , @ Res ( ) response ) { const user = await User . findOne ( { 'profile.lastName' : lastname , uid : uid , role : 'student' } ) ; if ( ! user ) { throw new BadRequestError ( errorCodes . errorCodes . user . userNotFound . code ) ; } if ( user . isActive ) { throw new BadRequestError ( errorCodes . errorCodes . user . userAlreadyActive . code ) ; } const timeSinceUpdate = ( Date . now ( ) - user . updatedAt . getTime ( ) ) / 60000 ; if ( timeSinceUpdate < Number ( config . timeTilNextActivationResendMin ) ) { const retryAfter = ( Number ( config . timeTilNextActivationResendMin ) - timeSinceUpdate ) * 60 ; response . set ( 'retry-after' , retryAfter . toString ( ) ) ; throw new HttpError ( 503 , errorCodes . errorCodes . user . retryAfter . code ) ; } const existingUser = await User . findOne ( { email : email } ) ; if ( existingUser && existingUser . uid !== uid ) { throw new BadRequestError ( errorCodes . errorCodes . mail . duplicate . code ) ; } user . authenticationToken = undefined ; user . email = email ; const savedUser = await user . save ( ) ; try { await emailService . resendActivation ( savedUser ) ; } catch ( err ) { throw new InternalServerError ( err . toString ( ) ) ; } } api apiName apiGroup apiParam apiParam apiSuccess apiSuccessExample apiError apiError @ Post ( '/reset' ) postPasswordReset ( @ BodyParam ( 'resetPasswordToken' ) resetPasswordToken , @ BodyParam ( 'newPassword' ) newPassword ) { return User . findOne ( { resetPasswordToken : resetPasswordToken } ) . then ( ( existingUser ) => { if ( ! existingUser ) { throw new HttpError ( 422 , 'could not reset users password' ) ; } if ( existingUser . resetPasswordExpires < new Date ( ) ) { throw new ForbiddenError ( 'your reset password token is expired' ) ; } existingUser . password = newPassword ; existingUser . resetPasswordToken = undefined ; existingUser . resetPasswordExpires = undefined ; existingUser . markModified ( 'password' ) ; return existingUser . save ( ) ; } ) . then ( ( savedUser ) => { return { success : true } ; } ) ; } api apiName apiGroup apiParam apiSuccess apiSuccessExample apiError apiError @ Post ( '/requestreset' ) postRequestPasswordReset ( @ BodyParam ( 'email' ) email ) { return User . findOne ( { email : email } ) . then ( ( existingUser ) => { if ( ! existingUser ) { throw new HttpError ( 422 , 'could not reset users password' ) ; } const expires = new Date ( ) ; expires . setTime ( ( new Date ( ) ) . getTime ( ) + ( 24 * 60 * 60 * 1000 ) ) ; existingUser . resetPasswordExpires = expires ; return existingUser . save ( ) ; } ) . then ( ( user ) => { return emailService . sendPasswordReset ( user ) ; } ) . then ( ( ) => { return { success : true } ; } ) . catch ( ( err ) => { throw new InternalServerError ( 'Could not send E-Mail' ) ; } ) ; } param { IUser } user returns { Promise < void > } private async addWhitelistedUserToCourses ( user ) { const courses = await Course . find ( { enrollType : 'whitelist' } ) . populate ( 'whitelist' ) ; await Promise . all ( courses . map ( async ( course ) => { const userUidIsRegisteredInWhitelist = course . whitelist . findIndex ( w => w . uid === user . uid ) >= 0 ; const userIsntAlreadyStudentOfCourse = course . students . findIndex ( u => u . _id === user . _id ) < 0 ; if ( userUidIsRegisteredInWhitelist && userIsntAlreadyStudentOfCourse ) { course . students . push ( user ) ; await course . save ( ) ; } } ) ) ; } }