sails-api-jwt
Version:
An example implementation of JWT-based API for user registration and authorization.
247 lines (206 loc) • 6 kB
JavaScript
/**
* UserController
*
* @description :: Server-side logic for managing Users
* @help :: See http://sailsjs.org/#!/documentation/concepts/Controllers
*/
const API_ERRORS = require('../constants/APIErrors');
const validator = require('validator');
const passValidator = require('password-validator');
const passSchema = new passValidator();
const passMinLen = 6;
const passMaxLen = 24;
// Scheme for password validation
// See ref https://github.com/tarunbatra/password-validator
passSchema
.is().min(passMinLen)
.is().max(passMaxLen)
.has().letters()
.has().digits();
module.exports = {
/**
* Action for /user
* @param req
* @param res
*/
index: function (req, res) {
// We use here req.userInfo which is set in policies/jwtAuth.js
res.ok({
id: req.userInfo.id,
email: req.userInfo.email
});
},
/**
* Action for /user/create
* @param req
* @param res
* @returns {*}
*/
create: function (req, res) {
const email = req.body.email;
const password = req.body.password;
const passwordConfirm = req.body.password_confirm;
if (!email || !validator.isEmail(email)) {
return res.badRequest(Utils.jsonErr('Invalid email'));
}
if (password !== passwordConfirm) {
return res.badRequest(Utils.jsonErr('Password does not match'));
}
if (!passSchema.validate(password)) {
return res.badRequest(Utils.jsonErr('Password must be 6-24 characters, including letters and digits'));
}
UserManager
.createUser({
email,
password
})
.then(jwToken => {
res.created({
token: jwToken
});
})
.catch(err => {
if (err === API_ERRORS.EMAIL_IN_USE) {
return res.badRequest(Utils.jsonErr('This email is already in use'));
}
/* istanbul ignore next */
return res.serverError(Utils.jsonErr(err));
});
},
/**
* Action for /user/login
* @param req
* @param res
* @returns {*}
*/
login: function (req, res) {
const email = req.body.email;
const password = req.body.password;
if (!email || !validator.isEmail(email)) {
return res.badRequest(Utils.jsonErr('Invalid email'));
}
if (!password) {
return res.badRequest(Utils.jsonErr('Invalid email or password'));
}
UserManager.authenticateUserByPassword(email, password)
.then(token => {
res.ok({token});
})
.catch(err => {
switch (err) {
case API_ERRORS.INVALID_EMAIL_PASSWORD:
case API_ERRORS.USER_NOT_FOUND:
return res.badRequest(Utils.jsonErr('Invalid email or password'));
case API_ERRORS.USER_LOCKED:
return res.forbidden(Utils.jsonErr('Account locked'));
default:
/* istanbul ignore next */
return res.serverError(Utils.jsonErr(err));
}
});
},
/**
* Action for /user/forgot
* @param req
* @param res
* @returns {*}
*/
forgotPassword: function (req, res) {
const email = req.body.email;
if (!email || !validator.isEmail(email)) {
return res.badRequest(Utils.jsonErr('Invalid email'));
}
UserManager
.generateResetToken(email)
.then(function () {
res.ok({message: 'Check your email'});
})
.catch(err => {
if (err === API_ERRORS.USER_NOT_FOUND) {
return res.notFound(Utils.jsonErr('User not found'));
}
/* istanbul ignore next */
return res.serverError(Utils.jsonErr(err));
});
},
/**
* Action for /user/change_password
* @param req
* @param res
* @returns {*}
*/
changePassword: function (req, res) {
const email = req.body.email;
const currentPassword = req.body.password;
const newPassword = req.body.new_password;
const newPasswordConfirm = req.body.new_password_confirm;
if (!email || !validator.isEmail(email)) {
return res.badRequest(Utils.jsonErr('Invalid email'));
}
if (!currentPassword) {
return res.badRequest(Utils.jsonErr('Current password is required'));
}
if (!newPassword || newPassword !== newPasswordConfirm) {
return res.badRequest(Utils.jsonErr('Password does not match'));
}
if (!passSchema.validate(newPassword)) {
return res.badRequest(Utils.jsonErr('Password must be 6-24 characters, including letters and digits'));
}
UserManager
.changePassword(email, currentPassword, newPassword)
.then(function (token) {
return res.ok({token});
})
.catch(err => {
switch (err) {
case API_ERRORS.USER_NOT_FOUND:
return res.badRequest(Utils.jsonErr('Email not found'));
// Processed by 'Invalid token' from policy
// case API_ERRORS.USER_LOCKED:
// return res.forbidden(Utils.jsonErr('Account locked'));
case API_ERRORS.INVALID_PASSWORD:
return res.badRequest(Utils.jsonErr('Invalid password'));
default:
/* istanbul ignore next */
return res.serverError(Utils.jsonErr(err));
}
});
},
/**
* Action for /user/reset_password
* @param req
* @param res
* @returns {*}
*/
resetPasswordByResetToken: function (req, res) {
const email = req.body.email;
const resetToken = req.body.reset_token;
const newPassword = req.body.new_password;
const newPasswordConfirm = req.body.new_password_confirm;
if (!email || !validator.isEmail(email)) {
return res.badRequest(Utils.jsonErr('Invalid email'));
}
if (!resetToken) {
return res.badRequest(Utils.jsonErr('Reset token is required'));
}
if (!newPassword || newPassword !== newPasswordConfirm) {
return res.badRequest(Utils.jsonErr('Password does not match'));
}
if (!passSchema.validate(newPassword)) {
return res.badRequest(Utils.jsonErr('Password must be 6-24 characters, including letters and digits'));
}
UserManager
.resetPasswordByResetToken(email, resetToken, newPassword)
.then(() => {
res.ok({message: 'Done'});
})
.catch(err => {
if (err === API_ERRORS.USER_NOT_FOUND) {
// We show invalid email instead of User Not Found
return res.badRequest(Utils.jsonErr('Invalid email'));
}
/* istanbul ignore next */
return res.serverError(Utils.jsonErr(err));
});
},
};