| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220 |
- 'use strict'
- require('dotenv').config()
- const Util = require('util')
- const Jwt = require('@hapi/jwt')
- const Schmervice = require('@hapipal/schmervice')
- const SecurePassword = require('secure-password')
-
- /** Class for methods used in the User plugin */
- module.exports = class UserService extends Schmervice.Service {
- /**
- * Unsure of what our constructor does
- * @param {...any} args
- */
- constructor(...args) {
- super(...args)
- const pwd = new SecurePassword()
- this.pwd = {
- hash: Util.promisify(pwd.hash.bind(pwd)),
- verify: Util.promisify(pwd.verify.bind(pwd)),
- }
- }
-
- /**
- * Use knex to find users with id column
- * @param {number} id
- * @param {*} txn
- * @returns
- */
- async findById(id, txn) {
- const { User } = this.server.models()
-
- return await User.query(txn)
- .throwIfNotFound()
- .first()
- .where({ user_id: id })
- }
-
- /**
- * Use knew to find first user with username
- * @param {*} username
- * @param {*} txn
- * @returns
- */
- async findByUsername(username, txn) {
- const { User } = this.server.models()
-
- return await User.query(txn)
- .throwIfNotFound()
- .first()
- .where({ user_name: username })
- }
-
- /**
- * Signup function
- * @param {*} param0
- * @param {*} txn
- * @returns
- */
- async signup({ password, userInfo }, txn) {
- const { User } = this.server.models()
- const matchingEmails = await User.query().where(
- 'user_email',
- userInfo.user_email,
- )
- if (matchingEmails.length > 0) {
- throw `User ${userInfo.user_email} already exists: Cannot create a user without a unique email`
- }
-
- // Library: Secure-Password
- const pepper = process.env.PEPPER
- // add pepper to pw
- const steak = password.trim() + pepper
- console.log(steak)
-
- const { Auth } = this.server.models()
- // send peppered pw to (argon algorithm) library for salted hash
- pwd.hash(steak, function (err, hash) {
- if (err) throw err
-
- // Save hash somewhere
- pwd.verify(steak, hash, function (err, result) {
- if (err) throw err
-
- switch (result) {
- case securePassword.INVALID_UNRECOGNIZED_HASH:
- return console.error('This hash was not made with secure-password. Attempt legacy algorithm')
- case securePassword.INVALID:
- return console.log('Invalid password')
- case securePassword.VALID:
- return console.log('Authenticated')
- case securePassword.VALID_NEEDS_REHASH:
- console.log('Yay you made it, wait for us to improve your safety')
-
- pwd.hash(userPassword, function (err, improvedHash) {
- if (err) console.error('You are authenticated, but we could not improve your safety this time around')
-
- // Save improvedHash somewhere
- // insert hash and salt into authentication table (with user, see 73)
- const saveHash = Auth.insert({ user_email: matchingEmails})
- .into('token')
-
- return saveHash
- })
- break
- }
- })
- })
-
- // const user = await User.query(txn).insert(userInfo)
- // user.user_id = user.id
- // delete user.id
- // await this.changePassword(id, password, txn)
- // return user
- }
-
- /**
- * Updates user's info
- * @param {number} id
- * @param {*} param1
- * @param {*} txn
- * @returns
- */
- async update(id, { password, ...userInfo }, txn) {
- const { User } = this.server.models()
-
- if (Object.keys(userInfo).length > 0) {
- await User.query(txn)
- .throwIfNotFound()
- .where({ id })
- .patch(userInfo)
- }
-
- if (password) {
- await this.changePassword(id, password, txn)
- }
-
- return id
- }
-
- /**
- * Self explanatory
- * @param {*} param0
- * @param {*} txn
- * @returns
- */
- async login({ email, password }, txn) {
- const { User } = this.server.models()
-
- const user = await User.query(txn)
- .throwIfNotFound()
- .first()
- .where({ user_email: email })
-
- /** Uncomment to run password check using SecurePassword */
- // const passwordCheck = await this.pwd.verify(Buffer.from(password), user.password)
- // if (passwordCheck === SecurePassword.VALID_NEEDS_REHASH) {
- // await this.changePassword(user.id, password, txn)
- // }
- // else if (passwordCheck !== SecurePassword.VALID) {
- // throw User.createNotFoundError()
- // }
-
- return user
- }
-
- /**
- * Create a token to be sent in request headers
- * @param {User} user
- * @returns {Token}
- */
- createToken(user) {
- const key = this.server.registrations['main-app-plugin'].options.jwtKey
-
- return Jwt.token.generate(
- {
- aud: 'urn:audience:test',
- iss: 'urn:issuer:test',
- email: user.user_email,
- },
- {
- key: key,
- algorithm: 'HS256',
- },
- {
- ttlSec: 4 * 60 * 60, // 7 days
- },
- )
- }
-
- /**
- * Use knex to try to change password entry
- * @param {number} id
- * @param {string} password
- * @param {*} txn
- * @returns {number}
- */
- async changePassword(id, password, txn) {
- const { User } = this.server.models()
- return 'done'
- // rework with Auth model
-
- // await User.query(txn)
- // .throwIfNotFound()
- // .where({ id })
- // .patch({
- // password: await this.pwd.hash(Buffer.from(password)),
- // })
- // return id
- }
-
- async getPassword(email, txn) {
- const { Auth } = this.server.models()
-
- const passwordRow = await Auth.query(txn)
- .where('user_email', email)
- .first()
-
- return passwordRow ? passwordRow.token : null
- }
- }
|