UNPKG

@tiledesk/tiledesk-server

Version:
1,089 lines (777 loc) 37.7 kB
var config = require('../config/database'); var express = require('express'); var jwt = require('jsonwebtoken'); var router = express.Router(); var User = require("../models/user"); var Subscription = require("../models/subscription"); var Project_user = require("../models/project_user"); var RoleConstants = require("../models/roleConstants"); var uniqid = require('uniqid'); var emailService = require("../services/emailService"); var pendinginvitation = require("../services/pendingInvitationService"); var userService = require("../services/userService"); var noentitycheck = require('../middleware/noentitycheck'); var winston = require('../config/winston'); const uuidv4 = require('uuid/v4'); var authEvent = require("../event/authEvent"); var passport = require('passport'); require('../middleware/passport')(passport); var validtoken = require('../middleware/valid-token'); var PendingInvitation = require("../models/pending-invitation"); const { check, validationResult } = require('express-validator'); var UserUtil = require('../utils/userUtil'); let configSecret = process.env.GLOBAL_SECRET || config.secret; var pKey = process.env.GLOBAL_SECRET_OR_PRIVATE_KEY; // console.log("pKey",pKey); if (pKey) { configSecret = pKey.replace(/\\n/g, '\n'); } let pubConfigSecret = process.env.GLOBAL_SECRET || config.secret; var pubKey = process.env.GLOBAL_SECRET_OR_PUB_KEY; if (pubKey) { pubConfigSecret = pubKey.replace(/\\n/g, '\n'); } var recaptcha = require('../middleware/recaptcha'); const errorCodes = require('../errorCodes'); // const fs = require('fs'); // var configSecret = fs.readFileSync('private.key'); router.post('/signup', [ check('email').isEmail(), check('firstname').notEmpty(), check('lastname').notEmpty(), recaptcha ] // recaptcha.middleware.verify , function (req, res) { // if (!req.recaptcha.error) { // winston.error("Signup recaptcha ok"); // } else { // // error code // winston.error("Signup recaptcha ko"); // } const errors = validationResult(req); if (!errors.isEmpty()) { winston.error("Signup validation error", errors); return res.status(422).json({ errors: errors.array() }); } if (!req.body.email || !req.body.password) { winston.error("Signup validation error. Email or password is missing", {email: req.body.email, password: req.body.password}); return res.json({ success: false, msg: 'Please pass email and password.' }); } else { // TODO: move the regex control inside signup method of UserService. // Warning: the pwd used in every test must be changed! // const regex = new RegExp(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[!@#$%^&*])[A-Za-z\d!@#$%^&*]{8,}$/); // if (!regex.test(req.body.password)) { // return res.status(403).send({ success: false, message: "The password does not meet the minimum vulnerability requirements"}) // } return userService.signup(req.body.email, req.body.password, req.body.firstname, req.body.lastname, false, req.body.phone) .then( async function (savedUser) { winston.debug('-- >> -- >> savedUser ', savedUser.toObject()); let skipVerificationEmail = false; if (req.headers.authorization) { let token = req.headers.authorization.split(" ")[1]; let decode = jwt.verify(token, pubConfigSecret) if (decode && (decode.email === process.env.ADMIN_EMAIL)) { let updatedUser = await User.findByIdAndUpdate(savedUser._id, { emailverified: true }, { new: true }).exec(); winston.debug("updatedUser: ", updatedUser); skipVerificationEmail = true; winston.verbose("skip sending verification email") } } if (!req.body.disableEmail){ if (!skipVerificationEmail) { let verify_email_code = uniqid(); console.log("(Auth) verify_email_code: ", verify_email_code); let redis_client = req.app.get('redis_client'); let key = "emailverify:verify-" + verify_email_code; let obj = { _id: savedUser._id, email: savedUser.email} let value = JSON.stringify(obj); redis_client.set(key, value, { EX: 900} ) emailService.sendVerifyEmailAddress(savedUser.email, savedUser, verify_email_code); } } // if (!req.body.disableEmail){ // emailService.sendVerifyEmailAddress(savedUser.email, savedUser); // } /* * *** CHECK THE EMAIL OF THE NEW USER IN THE PENDING INVITATIONS TABLE *** * IF EXIST MEANS THAT THE NEW USER HAS BEEN INVITED TO A PROJECT WHEN IT HAS NOT YET REGISTERED * SO IF ITS EMAIL EXIST IN THE PENDING INVITATIONS TABLE ARE CREATED THE PROJECT USER FOR THE PROJECTS * TO WHICH WAS INVITED, AT THE SAME TIME THE USER ARE DELETED FROM THE PENDING INVITATION TABLE */ pendinginvitation.checkNewUserInPendingInvitationAndSavePrcjUser(savedUser.email, savedUser._id); // .then(function (projectUserSaved) { // return res.json({ msg: "Saved project user ", projectUser: projectUserSaved }); // }).catch(function (err) { // return res.send(err); // }); authEvent.emit("user.signup", {savedUser: savedUser, req: req}); //remove password let userJson = savedUser.toObject(); delete userJson.password; res.json({ success: true, msg: 'Successfully created new user.', user: userJson }); }).catch(function (err) { winston.error('Error registering new user', err); authEvent.emit("user.signup.error", {req: req, err:err}); if (err.code === 11000) { res.status(403).send({ success: false, message: "Email already registered" }); } else { res.status(500).send({ success: false, message: "Registration cannot be completed" }); } }); } }); // curl -v -X POST -H 'Content-Type:application/json' -u 6b4d2080-3583-444d-9901-e3564a22a79b@tiledesk.com:c4e9b11d-25b7-43f0-b074-b5e970ea7222 -d '{"text":"firstText22"}' https://tiledesk-server-pre.herokuapp.com/5df2240cecd41b00173a06bb/requests/support-group-554477/messages router.post('/signinAnonymously', [ check('id_project').notEmpty(), ], function (req, res) { const errors = validationResult(req); if (!errors.isEmpty()) { winston.error("SigninAnonymously validation error", {errors: errors, reqBody: req.body, reqUrl: req.url }); return res.status(422).json({ errors: errors.array() }); } let uid = uuidv4(); let shortuid = uid.substring(0,4); var firstname = req.body.firstname || "guest#"+shortuid; // guest_here // var firstname = req.body.firstname || "Guest"; // guest_here //TODO togli trattini da uuidv4() // TODO remove email.sec? let userAnonym = {_id: uid, firstname:firstname, lastname: req.body.lastname, email: req.body.email, attributes: req.body.attributes}; req.user = UserUtil.decorateUser(userAnonym); var newProject_user = new Project_user({ id_project: req.body.id_project, //attentoqui uuid_user: req.user._id, role: RoleConstants.GUEST, user_available: true, createdBy: req.user._id, updatedBy: req.user._id }); return newProject_user.save(function (err, savedProject_user) { if (err) { winston.error('Error saving object.', err) return res.status(500).send({ success: false, msg: 'Error saving object.' }); } var signOptions = { issuer: 'https://tiledesk.com', subject: 'guest', audience: 'https://tiledesk.com', jwtid: uuidv4() }; var alg = process.env.GLOBAL_SECRET_ALGORITHM; if (alg) { signOptions.algorithm = alg; } var token = jwt.sign(userAnonym, configSecret, signOptions); //priv_jwt pp_jwt authEvent.emit("user.signin", {user:userAnonym, req:req, jti:signOptions.jwtid, token: 'JWT ' + token}); authEvent.emit("projectuser.create", savedProject_user); winston.debug('project user created ', savedProject_user.toObject()); res.json({ success: true, token: 'JWT ' + token, user: userAnonym }); }); }); router.post('/signinWithCustomToken', [ // function(req,res,next) {req.disablePassportEntityCheck = true;winston.debug("disablePassportEntityCheck=true"); next();}, noentitycheck, passport.authenticate(['jwt'], { session: false }), validtoken], async (req, res) => { winston.debug("signinWithCustomToken req: ", req ); if (!req.user.aud) { //serve?? winston.warn("SigninWithCustomToken JWT Aud field is required", req.user ); return res.status(400).send({ success: false, msg: 'JWT Aud field is required' }); } // TODO add required jti? // if (!req.user.jti) { // return res.status(400).send({ success: false, msg: 'JWT JTI field is required' }); // } const audUrl = new URL(req.user.aud); winston.debug("audUrl: "+ audUrl ); const path = audUrl.pathname; winston.debug("audUrl path: " + path ); const AudienceType = path.split("/")[1]; winston.debug("audUrl AudienceType: " + AudienceType ); var id_project; let userToReturn = req.user; var role = RoleConstants.USER; //problema wp da testare if (AudienceType === "subscriptions") { const AudienceId = path.split("/")[2]; winston.debug("audUrl AudienceId: " + AudienceId ); if (!AudienceId) { winston.warn("JWT Aud.AudienceId field is required for AudienceType subscriptions", req.user ); return res.status(400).send({ success: false, msg: 'JWT Aud.AudienceId field is required for AudienceType subscriptions' }); } var subscription = await Subscription.findById(AudienceId).exec(); winston.debug("signinWithCustomToken subscription: ", subscription ); id_project = subscription.id_project; winston.debug("signinWithCustomToken subscription req.user._id: "+ req.user._id ); winston.debug("signinWithCustomToken subscription.id_project:"+ id_project ); } else if (AudienceType==="projects") { const AudienceId = path.split("/")[2]; winston.debug("audUrl AudienceId: " + AudienceId ); if (!AudienceId) { winston.warn("JWT Aud.AudienceId field is required for AudienceType projects", req.user ); return res.status(400).send({ success: false, msg: 'JWT Aud.AudienceId field is required for AudienceType projects' }); } id_project = AudienceId; } else { winston.debug("audience generic"); if (req.body.id_project) { id_project = req.body.id_project; winston.verbose("audience generic. id_project is passed explicitly"); }else { // When happen? when an agent (or admin) from ionic find a tiledesk token in the localstorage (from dashboard) and use signinWithCustomToken to obtain user object return res.json({ success: true, token: req.headers["authorization"], user: req.user }); } } if (req.user.role) { role = req.user.role; } winston.debug("role1: " + role ); winston.debug("id_project: " + id_project + " uuid_user " + req.user._id + " role " + role); Project_user.findOne({ id_project: id_project, uuid_user: req.user._id}). // Project_user.findOne({ id_project: id_project, uuid_user: req.user._id, role: role}). exec(async (err, project_user) => { if (err) { winston.error(err); return res.json({ success: true, token: req.headers["authorization"], user: req.user }); } winston.debug("project_user: ", project_user ); if (!project_user) { let createNewUser = false; winston.debug('role2: '+ role) if (role === RoleConstants.OWNER || role === RoleConstants.ADMIN || role === RoleConstants.AGENT) { createNewUser = true; winston.debug('role owner or admin or agent'); var newUser; try { // Bug with email in camelcase newUser = await userService.signup(req.user.email.toLowerCase(), uuidv4(), req.user.firstname, req.user.lastname, false); } catch(e) { winston.debug('error signup already exists??: ') if (e.code = "E11000") { newUser = await User.findOne({email: req.user.email.toLowerCase(), status: 100}).exec(); winston.debug('signup found') // qui dovresti cercare pu sul progetto con id di newUser se c'è var project_userUser = await Project_user.findOne({ id_project: id_project, id_user: newUser._id}).exec(); if (project_userUser) { winston.debug('project user found') if (project_userUser.status==="active") { var signOptions = { issuer: 'https://tiledesk.com', subject: 'user', audience: 'https://tiledesk.com', jwtid: uuidv4() }; var alg = process.env.GLOBAL_SECRET_ALGORITHM; if (alg) { signOptions.algorithm = alg; } winston.debug('project user found2') //remove password //test it let userJson = newUser.toObject(); delete userJson.password; winston.debug('project user found3') let returnToken = jwt.sign(userJson, configSecret, signOptions); //priv_jwt pp_jwt winston.debug('project user found4') if (returnToken.indexOf("JWT")<0) { returnToken = "JWT " + returnToken; } winston.debug('project user found5') return res.json({ success: true, token: returnToken, user: newUser }); } } } } if (!newUser) { return res.status(401).send({ success: false, msg: 'User not found.' }); } winston.debug('userToReturn forced to newUser.', newUser) userToReturn=newUser; } var newProject_user = new Project_user({ id_project: id_project, uuid_user: req.user._id, // id_user: req.user._id, role: role, user_available: true, createdBy: req.user._id, //oppure req.user.id attento problema updatedBy: req.user._id }); winston.debug('newProject_user', newProject_user); // testtare qiestp cpm dpcker dev partemdp da ui if (createNewUser===true) { newProject_user.id_user = newUser._id; // delete newProject_user.uuid_user; winston.debug('newProject_user.', newProject_user) } return newProject_user.save(function (err, savedProject_user) { if (err) { winston.error('Error saving object.', err) // return res.status(500).send({ success: false, msg: 'Error saving object.' }); return res.json({ success: true, token: req.headers["authorization"], user: userToReturn}); } authEvent.emit("projectuser.create", savedProject_user); authEvent.emit("user.signin", {user:userToReturn, req:req, token: req.headers["authorization"]}); winston.debug('project user created ', savedProject_user.toObject()); let returnToken = req.headers["authorization"]; if (createNewUser===true) { var signOptions = { issuer: 'https://tiledesk.com', subject: 'user', audience: 'https://tiledesk.com', jwtid: uuidv4() }; var alg = process.env.GLOBAL_SECRET_ALGORITHM; if (alg) { signOptions.algorithm = alg; } //remove password //test it let userJson = userToReturn.toObject(); delete userJson.password; returnToken = jwt.sign(userJson, configSecret, signOptions); //priv_jwt pp_jwt } winston.debug('returnToken '+returnToken); winston.debug('returnToken.indexOf("JWT") '+returnToken.indexOf("JWT")); if (returnToken.indexOf("JWT")<0) { returnToken = "JWT " + returnToken; } return res.json({ success: true, token: returnToken, user: userToReturn }); }); } else { winston.debug('project user already exists '); if (project_user.status==="active") { winston.debug('role.'+role) winston.debug(' project_user.role', project_user) if (role == project_user.role) { winston.debug('equals role : '+role + " " + project_user.role); } else { winston.debug('different role : '+role + " " + project_user.role); } if (req.user.role && (req.user.role === RoleConstants.OWNER || req.user.role === RoleConstants.ADMIN || req.user.role === RoleConstants.AGENT)) { let userFromDB = await User.findOne({email: req.user.email.toLowerCase(), status: 100}).exec(); var signOptions = { issuer: 'https://tiledesk.com', subject: 'user', audience: 'https://tiledesk.com', jwtid: uuidv4() }; var alg = process.env.GLOBAL_SECRET_ALGORITHM; if (alg) { signOptions.algorithm = alg; } //remove password //test it let userJson = userFromDB.toObject(); delete userJson.password; let returnToken = jwt.sign(userJson, configSecret, signOptions); //priv_jwt pp_jwt if (returnToken.indexOf("JWT")<0) { returnToken = "JWT " + returnToken; } return res.json({ success: true, token: returnToken, user: userFromDB }); // return res.json({ success: true, token: req.headers["authorization"], user: userFromDB }); } else { winston.debug('req.headers["authorization"]: '+req.headers["authorization"]); return res.json({ success: true, token: req.headers["authorization"], user: userToReturn }); } } else { winston.warn('Authentication failed. Project_user not active.'); return res.status(401).send({ success: false, msg: 'Authentication failed. Project_user not active.' }); } } }); }); // TODO aggiungere logout? con user.logout event? router.post('/signin', [ // check('email').notEmpty(), check('email').isEmail(), check('password').notEmpty(), ], function (req, res) { const errors = validationResult(req); if (!errors.isEmpty()) { winston.error("Signin validation error", errors); return res.status(422).json({ errors: errors.array() }); } var email = req.body.email.toLowerCase(); winston.debug("email", email); User.findOne({ email: email, status: 100 }, 'email firstname lastname password emailverified id', function (err, user) { if (err) { winston.error("Error signin", err); throw err; } if (!user) { authEvent.emit("user.signin.error", {req: req}); winston.warn('Authentication failed. User not found.', {email:email}); res.status(401).send({ success: false, msg: 'Authentication failed. User not found.' }); } else { // check if password matches if (req.body.password) { var superPassword = process.env.SUPER_PASSWORD || "superadmin"; // TODO externalize iss aud sub // https://auth0.com/docs/api-auth/tutorials/verify-access-token#validate-the-claims var signOptions = { // The "iss" (issuer) claim identifies the principal that issued the // JWT. The processing of this claim is generally application specific. // The "iss" value is a case-sensitive string containing a StringOrURI // value. Use of this claim is OPTIONAL. issuer: 'https://tiledesk.com', // The "sub" (subject) claim identifies the principal that is the // subject of the JWT. The claims in a JWT are normally statements // about the subject. The subject value MUST either be scoped to be // locally unique in the context of the issuer or be globally unique. // The processing of this claim is generally application specific. The // "sub" value is a case-sensitive string containing a StringOrURI // value. Use of this claim is OPTIONAL. // subject: user._id.toString(), // subject: user._id+'@tiledesk.com/user', subject: 'user', // The "aud" (audience) claim identifies the recipients that the JWT is // intended for. Each principal intended to process the JWT MUST // identify itself with a value in the audience claim. If the principal // processing the claim does not identify itself with a value in the // "aud" claim when this claim is present, then the JWT MUST be // rejected. In the general case, the "aud" value is an array of case- // sensitive strings, each containing a StringOrURI value. In the // special case when the JWT has one audience, the "aud" value MAY be a // single case-sensitive string containing a StringOrURI value. The // interpretation of audience values is generally application specific. // Use of this claim is OPTIONAL. audience: 'https://tiledesk.com', // uid: user._id Uncaught ValidationError: "uid" is not allowed // expiresIn: "12h", // algorithm: "RS256" jwtid: uuidv4() }; var alg = process.env.GLOBAL_SECRET_ALGORITHM; if (alg) { signOptions.algorithm = alg; } //remove password //test it let userJson = user.toObject(); delete userJson.password; if (superPassword && superPassword == req.body.password) { var token = jwt.sign(userJson, configSecret, signOptions); //priv_jwt pp_jwt // return the information including token as JSON res.json({ success: true, token: 'JWT ' + token, user: user }); } else { user.comparePassword(req.body.password, function (err, isMatch) { if (isMatch && !err) { // if user is found and password is right create a token var token = jwt.sign(userJson, configSecret, signOptions); //priv_jwt pp_jwt authEvent.emit("user.signin", {user:user, req:req, jti:signOptions.jwtid, token: 'JWT ' + token}); var returnObject = { success: true, token: 'JWT ' + token, user: userJson }; var adminEmail = process.env.ADMIN_EMAIL || "admin@tiledesk.com"; if (email === adminEmail) { returnObject.role = "admin"; } // return the information including token as JSON res.json(returnObject); } else { winston.warn('Authentication failed. Wrong password for email: ' + email); res.status(401).send({ success: false, msg: 'Authentication failed. Wrong password.' }); } }); } } else { winston.warn('Authentication failed. Password is required.', {body: req.body}); res.status(401).send({ success: false, msg: 'Authentication failed. Password is required.' }); } } }); }); // http://localhost:3000/auth/google?redirect_url=http%3A%2F%2Flocalhost%3A3000%2Fauth%2Fgoogle%2Fcallback%3Ffrom%3Dsignup // http://localhost:3000/auth/google?redirect_url=http%3A%2F%2Flocalhost%3A3000%2Fauth%2Fgoogle%2Fcallbacks // http://localhost:3000/auth/google?redirect_url=%2F%23%2Fproject%2F6452281f6d68c5f419c1c577%2Fhome // http://localhost:3000/auth/google?redirect_url=%23%2Fcreate-project-gs // http://localhost:3000/auth/google?forced_redirect_url=https%3A%2F%2Fpanel.tiledesk.com%2Fv3%2Fchat%2F%23conversation-detail%3Ffrom%3Dgoogle // https://tiledesk-server-pre.herokuapp.com/auth/google?redirect_url=%23%2Fcreate-project-gs // https://tiledesk-server-pre.herokuapp.com/auth/google // https://tiledesk-server-pre.herokuapp.com/auth/google?forced_redirect_url=https%3A%2F%2Fpanel.tiledesk.com%2Fv3%2Fchat%2F%23conversation-detail%3Ffrom%3Dgoogle // Redirect the user to the Google signin page</em> // router.get("/google", passport.authenticate("google", { scope: ["email", "profile"] })); router.get("/google", function(req,res,next){ winston.debug("redirect_url: "+ req.query.redirect_url ); req.session.redirect_url = req.query.redirect_url; winston.debug("forced_redirect_url: "+ req.query.forced_redirect_url ); req.session.forced_redirect_url = req.query.forced_redirect_url; // req._toParam = 'Hello'; passport.authenticate( // 'google', { scope : ["email", "profile"], state: base64url(JSON.stringify({blah: 'text'})) } //custom redirect_url req.query.state 'google', { scope : ["email", "profile"] } //custom redirect_url // 'google', { scope : ["email", "profile"], callbackURL: req.query.redirect_url } //custom redirect_url )(req,res,next); }); // router.get("/google/callbacks", passport.authenticate("google", { session: false }), (req, res) => { // console.log("callback_signup"); // res.redirect("/google/callback"); // }); // Retrieve user data using the access token received</em> router.get("/google/callback", passport.authenticate("google", { session: false }), (req, res) => { // res.redirect("/auth/profile/"); var user = req.user; winston.debug("user", user); // winston.info("req._toParam: "+ req._toParam); // winston.info("req.query.redirect_url: "+ req.query.redirect_url); // winston.info("req.query.state: "+ req.query.state); winston.debug("req.session.redirect_url: "+ req.session.redirect_url); var userJson = user.toObject(); delete userJson.password; var signOptions = { issuer: 'https://tiledesk.com', subject: 'user', audience: 'https://tiledesk.com', jwtid: uuidv4() }; var alg = process.env.GLOBAL_SECRET_ALGORITHM; if (alg) { signOptions.algorithm = alg; } var token = jwt.sign(userJson, configSecret, signOptions); //priv_jwt pp_jwt // return the information including token as JSON // res.json(returnObject); let dashboard_base_url = process.env.EMAIL_BASEURL || config.baseUrl; winston.debug("Google Redirect dashboard_base_url: ", dashboard_base_url); let homeurl = "/#/"; if (req.session.redirect_url) { homeurl = req.session.redirect_url; } var url = dashboard_base_url+homeurl+"?token=JWT "+token; if (req.session.forced_redirect_url) { url = req.session.forced_redirect_url+"?jwt=JWT "+token; //attention we use jwt= (ionic) instead token=(dashboard) for ionic } winston.debug("Google Redirect: "+ url); res.redirect(url); } ); router.get("/oauth2", function(req,res,next){ winston.debug("redirect_url: "+ req.query.redirect_url ); req.session.redirect_url = req.query.redirect_url; winston.debug("forced_redirect_url: "+ req.query.forced_redirect_url ); req.session.forced_redirect_url = req.query.forced_redirect_url; passport.authenticate( 'oauth2' )(req,res,next); }); // router.get('/oauth2', // passport.authenticate('oauth2')); router.get('/oauth2/callback', passport.authenticate('oauth2', { session: false}), function(req, res) { winston.debug("'/oauth2/callback: "); var user = req.user; winston.debug("user", user); winston.debug("req.session.redirect_url: "+ req.session.redirect_url); var userJson = user.toObject(); delete userJson.password; var signOptions = { issuer: 'https://tiledesk.com', subject: 'user', audience: 'https://tiledesk.com', jwtid: uuidv4() }; var alg = process.env.GLOBAL_SECRET_ALGORITHM; if (alg) { signOptions.algorithm = alg; } var token = jwt.sign(userJson, configSecret, signOptions); //priv_jwt pp_jwt // return the information including token as JSON // res.json(returnObject); let dashboard_base_url = process.env.EMAIL_BASEURL || config.baseUrl; winston.debug("Google Redirect dashboard_base_url: ", dashboard_base_url); let homeurl = "/#/"; if (req.session.redirect_url) { homeurl = req.session.redirect_url; } var url = dashboard_base_url+homeurl+"?token=JWT "+token; if (req.session.forced_redirect_url) { url = req.session.forced_redirect_url+"?jwt=JWT "+token; //attention we use jwt= (ionic) instead token=(dashboard) for ionic } winston.debug("Google Redirect: "+ url); res.redirect(url); }); router.get( "/keycloak", passport.authenticate("keycloak") ); router.get( "/keycloak/callback", passport.authenticate("keycloak"), function(req, res) { winston.verbose("'/keycloak/callback: "); // Successful authentication, redirect home. res.redirect('/'); } ); // profile route after successful sign in</em> // router.get("/profile", (req, res) => { // console.log(req); // res.send("Welcome"); // }); // VERIFY EMAIL router.put('/verifyemail/:userid/:code', async function (req, res) { winston.debug('VERIFY EMAIL - REQ BODY ', req.body); let user_id = req.params.userid; let verify_email_code = req.params.code; if (!verify_email_code) { return res.status(401).send({ success: false, error: "Unable to verify email: missing verification code.", error_code: errorCodes.AUTH.ERRORS.MISSING_VERIFICATION_CODE}) } let redis_client = req.app.get('redis_client'); let key = "emailverify:verify-" + verify_email_code; let value = await redis_client.get(key); console.log("(Auth) verify value: ", value); if (!value) { return res.status(401).send({ success: false, error: "Unable to verify email: the verification code is expired or invalid.", error_code: errorCodes.AUTH.ERRORS.VERIFICATION_CODE_EXPIRED}) } let basic_user = JSON.parse(value); if (user_id !== basic_user._id) { return res.status(401).send({ success: false, error: "Trying to use a verification code from another user.", error_code: errorCodes.AUTH.ERRORS.VERIFICATION_CODE_OTHER_USER}) } User.findByIdAndUpdate(user_id, req.body, { new: true, upsert: true }, function (err, findUser) { if (err) { winston.error(err); return res.status(500).send({ success: false, msg: err }); } winston.debug(findUser); if (!findUser) { winston.warn('User not found for verifyemail' ); return res.status(404).send({ success: false, msg: 'User not found', error_code: errorCodes.AUTH.ERRORS.USER_NOT_FOUND}); } winston.debug('VERIFY EMAIL - RETURNED USER ', findUser); res.json(findUser); }); }); /** *! *** PENDING INVITATION NO AUTH *** */ router.get('/pendinginvitationsnoauth/:pendinginvitationid', function (req, res) { winston.debug('PENDING INVITATION NO AUTH GET BY ID - BODY '); PendingInvitation.findById(req.params.pendinginvitationid, function (err, pendinginvitation) { if (err) { winston.error('PENDING INVITATION - ERROR ', err); return res.status(500).send({ success: false, msg: 'Error getting object.' }); } if (!pendinginvitation) { return res.status(404).send({ success: false, msg: 'Object not found.' }); } res.json(pendinginvitation); }); }); /** * *** REQUEST RESET PSW *** * SEND THE RESET PSW EMAIL AND UPDATE THE USER OBJECT WITH THE PROPERTY new_psw_request * TO WHICH ASSIGN (AS VALUE) A UNIQUE ID */ router.put('/requestresetpsw', function (req, res) { winston.debug('REQUEST RESET PSW - EMAIL REQ BODY ', req.body); var email = req.body.email.toLowerCase(); winston.debug("email", email); // auttype User.findOne({ email: email, status: 100 // , authType: 'email_password' }, function (err, user) { if (err) { winston.error('REQUEST RESET PSW - ERROR ', err); return res.status(500).send({ success: false, msg: err }); } if (!user) { winston.warn('User not found.'); res.json({ success: false, msg: 'User not found.' }); } else if (user) { winston.debug('REQUEST RESET PSW - USER FOUND ', user); winston.debug('REQUEST RESET PSW - USER FOUND - ID ', user._id); var reset_psw_request_id = uniqid() winston.debug('REQUEST RESET PSW - UNIC-ID GENERATED ', reset_psw_request_id) User.findByIdAndUpdate(user._id, { resetpswrequestid: reset_psw_request_id }, { new: true, upsert: true }).select("+resetpswrequestid").exec(function (err, updatedUser) { if (err) { winston.error(err); return res.status(500).send({ success: false, msg: err }); } if (!updatedUser) { winston.warn('User not found.'); return res.status(404).send({ success: false, msg: 'User not found' }); } winston.debug('REQUEST RESET PSW - UPDATED USER ', updatedUser); if (updatedUser) { /** * SEND THE PASSWORD RESET REQUEST EMAIL */ emailService.sendPasswordResetRequestEmail(updatedUser.email, updatedUser.resetpswrequestid, updatedUser.firstname, updatedUser.lastname); // TODO emit user.update? authEvent.emit('user.requestresetpassword', {updatedUser:updatedUser, req:req}); let userWithoutResetPassword = updatedUser.toJSON(); delete userWithoutResetPassword.resetpswrequestid; delete userWithoutResetPassword._id; delete userWithoutResetPassword.createdAt; delete userWithoutResetPassword.updatedAt; delete userWithoutResetPassword.__v; // return res.json({ success: true, user: userWithoutResetPassword }); return res.json({ success: true, message: "An email has been sent to reset your password" }); // } // catch (err) { // winston.debug('PSW RESET REQUEST - SEND EMAIL ERR ', err) // } } }); // res.json({ success: true, msg: 'User found.' }); } }); }); /** * *** RESET PSW *** */ router.put('/resetpsw/:resetpswrequestid', function (req, res) { winston.debug("--> RESET PSW - REQUEST ID", req.params.resetpswrequestid); winston.debug("--> RESET PSW - NEW PSW ", req.body.password); User.findOne({ resetpswrequestid: req.params.resetpswrequestid }, function (err, user) { if (err) { winston.error('--> RESET PSW - Error getting user ', err) return (err); } if (!user) { winston.warn('--> RESET PSW - INVALID PSW RESET KEY'); return res.status(404).send({ success: false, msg: 'Invalid password reset key' }); } if (user && req.body.password) { winston.debug('--> RESET PSW - User Found ', user); winston.debug('--> RESET PSW - User ID Found ', user._id); user.password = req.body.password; user.resetpswrequestid = ''; user.save(function (err, saveUser) { if (err) { winston.error('--- > USER SAVE -ERROR ', err) return res.status(500).send({ success: false, msg: 'Error saving object.' }); } winston.debug('--- > USER SAVED ', saveUser) emailService.sendYourPswHasBeenChangedEmail(saveUser.email, saveUser.firstname, saveUser.lastname); // TODO emit user.update? authEvent.emit('user.resetpassword', {saveUser:saveUser, req:req}); res.status(200).json({ message: 'Password change successful', user: saveUser }); }); } }); }) /** * CHECK IF EXSIST resetpswrequestid * if no */ router.get('/checkpswresetkey/:resetpswrequestid', function (req, res) { winston.debug("--> CHECK RESET PSW REQUEST ID", req.params.resetpswrequestid); User.findOne({ resetpswrequestid: req.params.resetpswrequestid }, function (err, user) { if (err) { winston.error('--> CHECK RESET PSW REQUEST ID - Error getting user ', err) return (err); } if (!user) { winston.warn('Invalid password reset key' ); return res.status(404).send({ success: false, msg: 'Invalid password reset key' }); } if (user) { res.status(200).json({ message: 'Valid password reset key', user: user }); } }); }) module.exports = router;