Files
bigcapital/server/src/http/controllers/Authentication.js
Ahmed Bouhuolia 70809cb05c WIP Items module.
2019-09-03 02:07:28 +02:00

185 lines
5.0 KiB
JavaScript

import express from 'express';
import { check, validationResult } from 'express-validator';
import path from 'path';
import fs from 'fs';
import Mustache from 'mustache';
import User from '@/models/User';
import asyncMiddleware from '../middleware/asyncMiddleware';
import PasswordReset from '@/models/PasswordReset';
import mail from '@/services/mail';
import { hashPassword } from '@/utils';
export default {
/**
* Constructor method.
*/
router() {
const router = express.Router();
router.post('/login',
this.login.validation,
asyncMiddleware(this.login.handler));
router.post('/send_reset_password',
this.sendResetPassword.validation,
asyncMiddleware(this.sendResetPassword.handler));
router.post('/reset/:token',
this.resetPassword.validation,
asyncMiddleware(this.resetPassword.handler));
return router;
},
/**
* User login authentication request.
*/
login: {
validation: [
check('crediential').isEmail(),
check('password').isLength({ min: 5 }),
],
async handler(req, res) {
const validationErrors = validationResult(req);
if (!validationErrors.isEmpty()) {
return res.boom.badData(null, {
code: 'validation_error',
...validationErrors,
});
}
const { crediential, password } = req.body;
const user = await User.query({
where: { email: crediential },
orWhere: { phone_number: crediential },
}).fetch();
if (!user) {
return res.boom.badRequest(null, {
errors: [{ type: 'INVALID_DETAILS', code: 100 }],
});
}
if (!user.verifyPassword(password)) {
return res.boom.badRequest(null, {
errors: [{ type: 'INCORRECT_PASSWORD', code: 110 }],
});
}
if (!user.attributes.active) {
return res.boom.badRequest(null, {
errors: [{ type: 'USER_INACTIVE', code: 120 }],
});
}
user.save({ alst_login_at: new Date() });
return res.status(200).send({});
},
},
/**
* Send reset password link via email or SMS.
*/
sendResetPassword: {
validation: [
check('email').isEmail(),
],
// eslint-disable-next-line consistent-return
async handler(req, res) {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(422).json({ errors: errors.array() });
}
const { email } = req.body;
const user = User.where('email').fetch();
if (!user) {
return res.status(422).send();
}
// Delete all stored tokens of reset password that associate to the give email.
await PasswordReset.where({ email }).destroy({ require: false });
const passwordReset = PasswordReset.forge({
email,
token: '123123',
});
await passwordReset.save();
const filePath = path.join(__dirname, '../../views/mail/ResetPassword.html');
const template = fs.readFileSync(filePath, 'utf8');
const rendered = Mustache.render(template, {
url: `${req.protocol}://${req.hostname}/reset/${passwordReset.attributes.token}`,
first_name: user.attributes.first_name,
last_name: user.attributes.last_name,
contact_us_email: process.env.CONTACT_US_EMAIL,
});
const mailOptions = {
to: user.attributes.email,
from: `${process.env.MAIL_FROM_NAME} ${process.env.MAIL_FROM_ADDRESS}`,
subject: 'Ratteb Password Reset',
html: rendered,
};
// eslint-disable-next-line consistent-return
mail.sendMail(mailOptions, (error) => {
if (error) {
return res.status(400).send();
}
res.status(200).send({ data: { email: passwordReset.attributes.email } });
});
},
},
/**
* Reset password.
*/
resetPassword: {
validation: [
check('password').isLength({ min: 5 }),
check('reset_password'),
],
async handler(req, res) {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(422).json({ errors: errors.array() });
}
const { token } = req.params;
const { password } = req.body;
const tokenModel = await PasswordReset.query((query) => {
query.where({ token });
query.where('created_at', '>=', Date.now() - 3600000);
}).fetch();
if (!tokenModel) {
return res.status(400).send({
error: {
type: 'token.invalid',
message: 'Password reset token is invalid or has expired',
},
});
}
const user = await User.where({
email: tokenModel.attributes.email,
});
if (!user) {
return res.status(400).send({
error: { message: 'An unexpected error occurred.' },
});
}
const hashedPassword = await hashPassword(password);
user.set('password', hashedPassword);
await user.save();
await PasswordReset.where('email', user.get('email')).destroy({ require: false });
return res.status(200).send({});
},
},
};