Added user passwords

This commit is contained in:
Jori Lallo 2016-09-11 17:47:22 -07:00
parent 43e60aacaf
commit 0e7c216735
5 changed files with 76 additions and 3 deletions

View File

@ -62,6 +62,7 @@
"babel-preset-react-hmre": "1.1.1",
"babel-preset-stage-0": "6.5.0",
"babel-regenerator-runtime": "6.5.0",
"bcrypt": "^0.8.7",
"bugsnag": "^1.7.0",
"classnames": "2.2.3",
"codemirror": "5.16.0",

View File

@ -1,5 +1,3 @@
'use strict';
module.exports = {
up: function (queryInterface, Sequelize) {
queryInterface.changeColumn(
@ -42,5 +40,5 @@ module.exports = {
allowNull: true,
}
);
}
},
};

View File

@ -0,0 +1,12 @@
module.exports = {
up: (queryInterface, Sequelize) => {
queryInterface.addColumn('users', 'passwordDigest', {
type: Sequelize.STRING,
allowNull: true,
});
},
down: (queryInterface, _Sequelize) => {
queryInterface.removeColumn('users', 'passwordDigest');
},
};

View File

@ -1,4 +1,5 @@
import crypto from 'crypto';
import bcrypt from 'bcrypt';
import {
DataTypes,
sequelize,
@ -7,11 +8,15 @@ import {
import JWT from 'jsonwebtoken';
const BCRYPT_COST = process.env.NODE_ENV !== 'production' ? 4 : 12;
const User = sequelize.define('user', {
id: { type: DataTypes.UUID, defaultValue: DataTypes.UUIDV4, primaryKey: true },
email: { type: DataTypes.STRING, unique: true },
username: { type: DataTypes.STRING, unique: true },
name: DataTypes.STRING,
password: DataTypes.VIRTUAL,
passwordDigest: DataTypes.STRING,
isAdmin: DataTypes.BOOLEAN,
slackAccessToken: encryptedFields.vault('slackAccessToken'),
slackId: { type: DataTypes.STRING, allowNull: true },
@ -25,6 +30,23 @@ const User = sequelize.define('user', {
async getTeam() {
return this.team;
},
verifyPassword(password) {
return new Promise((resolve, reject) => {
if (!this.passwordDigest) {
resolve(false);
return;
}
bcrypt.compare(password, this.passwordDigest, (err, ok) => {
if (err) {
reject(err);
return;
}
resolve(ok);
});
});
},
},
indexes: [
{
@ -36,7 +58,25 @@ const User = sequelize.define('user', {
const setRandomJwtSecret = (model) => {
model.jwtSecret = crypto.randomBytes(64).toString('hex');
};
const hashPassword = function hashPassword(model) {
if (!model.password) {
return null;
}
return new Promise((resolve, reject) => {
bcrypt.hash(model.password, BCRYPT_COST, (err, digest) => {
if (err) {
reject(err);
return;
}
model.passwordDigest = digest;
resolve();
});
});
};
User.beforeCreate(hashPassword);
User.beforeUpdate(hashPassword);
User.beforeCreate(setRandomJwtSecret);
export default User;

View File

@ -0,0 +1,22 @@
import { User } from '.';
import { flushdb, sequelize } from '../test/support';
beforeEach(flushdb);
afterAll(() => sequelize.close());
it('should set JWT secret and password digest', async () => {
const user = User.build({
username: 'user',
name: 'User',
email: 'user1@example.com',
password: 'test123!',
});
await user.save();
expect(user.passwordDigest).toBeTruthy();
expect(user.getJwtToken()).toBeTruthy();
expect(await user.verifyPassword('test123!')).toBe(true);
expect(await user.verifyPassword('badPasswd')).toBe(false);
});