Architecture Diagram ( IMG 1 )
Install via NPM
npm install bcrypt
npm install sequelize
Usage with Sequelize Model
const bcrypt = require('bcrypt');
var userSchema = sequelize.define("users", {
userId: {
field: 'user_id',
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
password: {
field: 'user_password',
type: Sequelize.STRING,
allowNull: true
},
name: {
type: Sequelize.STRING,
field: 'user_name',
allowNull: false
},
email: {
type: Sequelize.STRING,
field: 'user_email',
allowNull: false
},
},
{
hooks: {
beforeCreate: async (user) => {
if (user.password) {
const salt = await bcrypt.genSaltSync(10, 'a');
user.password = bcrypt.hashSync(user.password, salt);
}
},
beforeUpdate:async (user) => {
if (user.password) {
const salt = await bcrypt.genSaltSync(10, 'a');
user.password = bcrypt.hashSync(user.password, salt);
}
}
},
instanceMethods: {
validPassword: (password) => {
return bcrypt.compareSync(password, this.password);
}
}
});
userSchema.prototype.validPassword = async (password, hash) => {
return await bcrypt.compareSync(password, hash);
}
return userSchema;
}
Validate Password
const authenticateUserWithemail = (user) => {
return new Promise((resolve, reject) => {
try {
usermodel.findOne({
where: {
user_email: user.userName // user email
}
}).then(async (response) => {
if (!response) {
resolve(false);
} else {
if (!response.dataValues.password ||
!await response.validPassword(user.password,
response.dataValues.password)) {
resolve(false);
} else {
resolve(response.dataValues)
}
}
})
} catch (error) {
const response = {
status: 500,
data: {},
error: {
message: "user match failed"
}
};
reject(response);
}
})
}
Sequelize Model
Models are the essence of Sequelize. A model is an abstraction that represents a table in your database. In Sequelize, it is a class that extends Model.
The model tells Sequelize several things about the entity it represents, such as the name of the table in the database and which columns it has (and their data types).
A model in Sequelize has a name. This name does not have to be the same name of the table it represents in the database. Usually, models have singular names (such as User
) while tables have pluralized names (such as Users
), although this is fully configurable.
Sequelize hooks
Hooks (also known as lifecycle events), are functions which are called before and after calls in sequelize are executed. For example, if you want to always set a value on a model before saving it, you can add a beforeUpdate
hook.
Note: You can't use hooks with instances. Hooks are used with models.
beforeCreate
Initialized before entity creation.
beforeUpdate
Initialized before entity updation.
Hooks firing order
The diagram below shows the firing order for the most common hooks.
Note: this list is not exhaustive.
(1)
beforeBulkCreate(instances, options)
beforeBulkDestroy(options)
beforeBulkUpdate(options)
(2)
beforeValidate(instance, options)
[... validation happens ...]
(3)
afterValidate(instance, options)
validationFailed(instance, options, error)
(4)
beforeCreate(instance, options)
beforeDestroy(instance, options)
beforeUpdate(instance, options)
beforeSave(instance, options)
beforeUpsert(values, options)
[... creation/update/destruction happens ...]
(5)
afterCreate(instance, options)
afterDestroy(instance, options)
afterUpdate(instance, options)
afterSave(instance, options)
afterUpsert(created, options)
(6)
afterBulkCreate(instances, options)
afterBulkDestroy(options)
afterBulkUpdate(options)
instanceMethods
Instance methods are methods that are available on instances of the model. We often write these to get information or do something related to that instance.
Definition
const Pug = db.define('pugs', {*/* etc*/*})
// instance methods are defined on the model's .prototype
Pug.prototype.celebrateBirthday = function () {
// 'this' in an instance method refers to the instance itself
const birthday = new Date(this.birthday)
const today = new Date()
if (birthday.getMonth() === today.getMonth() && today.getDate() === birthday.getDate()) {
console.log('Happy birthday!')
}
}
Usage
const createdPug = await Pug.create({name: 'Cody'}) // let's say `birthday` defaults to today
// the instance method is invoked *on the instance*
createdPug.celebrateBirthday() // Happy birthday!
Class Methods
Class methods are methods that are available on the model itself (aka the class). We often write these to get instances, or do something to more than one instance.
Definition
const Pug = db.define('pugs', {*/* etc*/*})
// class methods are defined right on the model
Pug.findPuppies = function () {
// 'this' refers directly back to the model (the capital "P" Pug)
return this.findAll({ // could also be Pug.findAll
where: {
age: {$lte: 1} // find all pugs where age is less than or equal to 1
}
})
}
Usage
const* foundPuppies = await Pug.findPuppies()
console.log('Here are the pups: ', foundPuppies)
bcrypt
Is a password-hashing function designed by Niels Provos and David Mazières, based on the Blowfish cipher and presented at USENIX in 1999. Besides incorporating a salt to protect against rainbow table attacks, bcrypt is an adaptive function: over time, the iteration count can be increased to make it slower, so it remains resistant to brute-force search attacks even with increasing computation power.
The bcrypt function is the default password hash algorithm for OpenBSD and other systems including some Linux distributions such as SUSE Linux.
bcrypy API
genSaltSync(rounds, minor) rounds — [OPTIONAL] — the cost of processing the data. (default — 10)
minor — [OPTIONAL] — minor version of bcrypt to use. (default — b)
genSalt(rounds, minor, cb)
rounds — [OPTIONAL] — the cost of processing the data. (default — 10)
minor — [OPTIONAL] — minor version of bcrypt to use. (default — b)
cb — [OPTIONAL] — a callback to be fired once the salt has been generated. uses eio making it asynchronous. If cb is not specified, a Promise is returned if Promise support is available.
err — First parameter to the callback detailing any errors.
salt — Second parameter to the callback providing the generated salt.
hashSync(data, salt)
data — [REQUIRED] — the data to be encrypted.
salt — [REQUIRED] — the salt to be used to hash the password. if specified as a number then a salt will be generated with the specified number of rounds and used (see example under Usage).
hash(data, salt, cb)
data — [REQUIRED] — the data to be encrypted.
salt— [REQUIRED] — the salt to be used to hash the password. if specified as a number then a salt will be generated with the specified number of rounds and used (see example under Usage).
cb — [OPTIONAL] — a callback to be fired once the data has been encrypted. uses eio making it asynchronous. If cb is not specified, a Promise is returned if Promise support is available.
err — First parameter to the callback detailing any errors.
encrypted — Second parameter to the callback providing the encrypted form.
compareSync(data, encrypted)
data — [REQUIRED] — data to compare.
encrypted — [REQUIRED] — data to be compared to.
compare(data, encrypted, cb)
data — [REQUIRED] — data to compare.
encrypted — [REQUIRED] — data to be compared to.
cb — [OPTIONAL] — a callback to be fired once the data has been compared. uses eio making it asynchronous. If cb is not specified, a Promise is returned if Promise support is available.
err — First parameter to the callback detailing any errors.
same — Second parameter to the callback providing whether the data and encrypted forms match [true | false].
getRounds(encrypted) — return the number of rounds used to encrypt a given hash.
encrypted — [REQUIRED] — hash from which the number of rounds used should be extracted.
That's it for this post. Hope you found it helpful and thank you for reading.