Skip to content

Instantly share code, notes, and snippets.

@dron247
Created December 8, 2018 15:26
Show Gist options
  • Save dron247/d6befada2708a256f40d97041650f2ba to your computer and use it in GitHub Desktop.
Save dron247/d6befada2708a256f40d97041650f2ba to your computer and use it in GitHub Desktop.
Студентам: Простая реализация репозитория в ноде, поверх mongo
'use strict'
const bcrypt = require('bcrypt')
const jwt = require('jsonwebtoken')
const Joi = require('joi')
const credentialsSchema = require('../schema/credentials')
module.exports = (database) => {
const collectionName = process.env.DB_USERS_COLLECTION_NAME
const secret = process.env.JWT_SECRET
const saltRounds = Number(process.env.PASSWORD_SALT_ROUNDS)
const collection = database.collection(collectionName)
/**
* Creates a new user, returns a promise which resolves into JWT token
* @param {*} credentials an object with {username:String, password: String}
*/
function create(credentials) {
return new Promise((resolve, reject) => {
const result = Joi.validate(credentials, credentialsSchema)
if (result.error) {
return reject(result.error)
}
try {
const token = createUserInternal(collection, credentials, secret, saltRounds)
return resolve(token)
} catch (error) {
return reject(error)
}
})
}
/**
* Performs user login, returns a promise which resolves into JWT token, or throws an error
* @param {*} credentials an object with {username:String, password: String}
*/
function login(credentials) {
return new Promise((resolve, reject) => {
const result = Joi.validate(credentials, credentialsSchema)
if (result.error) {
return reject(result.error)
}
try {
const token = loginInternal(collection, credentials, secret)
return resolve(token)
} catch (error) {
return reject(error)
}
})
}
async function loginInternal(collection, credentials, secret) {
const user = await collection.findOne({
name: credentials.name
})
if (!user) {
throw 'invalid user name'
}
const isPasswordOk = await bcrypt.compare(credentials.password, user.passwordHash)
if (!isPasswordOk) {
throw 'invalid password'
}
return sign(credentials, secret)
}
async function createUserInternal(collection, credentials, secret, saltRounds) {
const hashedPassword = await bcrypt.hash(credentials.password, saltRounds)
const user = {
name: credentials.name,
passwordHash: hashedPassword
}
await collection.insertOne(user)
return sign(credentials, secret)
}
function sign(credentials, secret) {
return jwt.sign({
exp: Math.floor(Date.now() / 1000) + (60 * 60), // 1 hour from now
data: {
name: credentials.name
}
}, secret)
}
return Object.assign({}, {
create,
login
})
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment