78 lines
2.2 KiB
Markdown
78 lines
2.2 KiB
Markdown
|
# Scrypt Wrapper
|
||
|
|
||
|
NodeJS's standard library's `crypto` module contains an `scrypt` function,
|
||
|
which uses the Scrypt password-based key derivation function to create a hash
|
||
|
which can be stored to later verify a password's validity. This library is a
|
||
|
thin wrapper around that function which handles salting, serializing and
|
||
|
deserializing hash metadata, and verification. It contains both asynchronous
|
||
|
and synchronous versions of its functions, and is thoroughly tested.
|
||
|
|
||
|
## Usage
|
||
|
|
||
|
```javascript
|
||
|
const { hash, verify } = require('@techworkers/scrypt-wrapper')
|
||
|
const userEnteredPassword = 'some password'
|
||
|
const hashedPassword = await hash(userEnteredPassword)
|
||
|
if (await verify(hashedPassword, userEnteredPassword)) {
|
||
|
// allowed!
|
||
|
}
|
||
|
```
|
||
|
|
||
|
Or, in a synchronous environment...
|
||
|
|
||
|
```javascript
|
||
|
const { hashSync, verifySync } = require('@techworkers/scrypt-wrapper')
|
||
|
const userEnteredPassword = 'some password'
|
||
|
const hashedPassword = hashSync(userEnteredPassword)
|
||
|
if (verifySync(hashedPassword, userEnteredPassword)) {
|
||
|
// allowed!
|
||
|
}
|
||
|
```
|
||
|
|
||
|
Async and sync versions can be used together. For example, Sequelize doesn't
|
||
|
offer async setters:
|
||
|
|
||
|
```javascript
|
||
|
const sequelize = require('sequelize')
|
||
|
const { Model } = sequelize
|
||
|
const { hashSync, verify } = require('@techworkers/scrypt-wrapper')
|
||
|
module.exports = (sequelize, DataTypes) => {
|
||
|
class User extends Model {
|
||
|
static async authenticated(name, password) {
|
||
|
const user = await User.findOne({ where: { name } })
|
||
|
if (!user) return null
|
||
|
if (await verify(user.password, password)) return user
|
||
|
else return null
|
||
|
}
|
||
|
}
|
||
|
User.init(
|
||
|
{
|
||
|
name: DataTypes.STRING,
|
||
|
password: {
|
||
|
type: DataTypes.STRING,
|
||
|
set(password) {
|
||
|
if (!password) throw `invalid password <${password}>`
|
||
|
this.setDataValue('password', hashSync(password))
|
||
|
// We need to generate the hash ^^^ value synchronously here
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
sequelize,
|
||
|
tableName: 'Users',
|
||
|
modelName: 'User',
|
||
|
underscored: true,
|
||
|
},
|
||
|
)
|
||
|
return User
|
||
|
}
|
||
|
|
||
|
// Creating a user
|
||
|
const user = await User.create({name: 'user', password: 'monkey'})
|
||
|
// Validating them
|
||
|
const reFetchedUser = await User.authenticated('user', 'monkey')
|
||
|
```
|
||
|
|
||
|
## Tests
|
||
|
|
||
|
Run tests with `yarn test`.
|