You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. 'use strict';
  2. const Util = require('util');
  3. const Jwt = require('@hapi/jwt');
  4. const Schmervice = require('@hapipal/schmervice');
  5. const SecurePassword = require('secure-password');
  6. module.exports = class UserService extends Schmervice.Service {
  7. constructor(...args) {
  8. super(...args)
  9. const pwd = new SecurePassword()
  10. this.pwd = {
  11. hash: Util.promisify(pwd.hash.bind(pwd)),
  12. verify: Util.promisify(pwd.verify.bind(pwd))
  13. }
  14. }
  15. async findById(id, txn) {
  16. const { User } = this.server.models()
  17. return await User.query(txn).throwIfNotFound().findById(id)
  18. }
  19. async findByUsername(username, txn) {
  20. const { User } = this.server.models()
  21. return await User.query(txn).throwIfNotFound().first().where({ username })
  22. }
  23. async signup({ password, ...userInfo }, txn) {
  24. const { User } = this.server.models()
  25. const { id } = await User.query(txn).insert(userInfo)
  26. await this.changePassword(id, password, txn)
  27. return id
  28. }
  29. async update(id, { password, ...userInfo }, txn) {
  30. const { User } = this.server.models()
  31. if (Object.keys(userInfo).length > 0) {
  32. await User.query(txn).throwIfNotFound().where({ id }).patch(userInfo)
  33. }
  34. if (password) {
  35. await this.changePassword(id, password, txn)
  36. }
  37. return id
  38. }
  39. async login({ email, password }, txn) {
  40. const { User } = this.server.models()
  41. const user = await User.query(txn).throwIfNotFound().first().where({
  42. email: User.raw('? collate nocase', email)
  43. })
  44. const passwordCheck = await this.pwd.verify(Buffer.from(password), user.password)
  45. if (passwordCheck === SecurePassword.VALID_NEEDS_REHASH) {
  46. await this.changePassword(user.id, password, txn)
  47. }
  48. else if (passwordCheck !== SecurePassword.VALID) {
  49. throw User.createNotFoundError()
  50. }
  51. return user
  52. }
  53. createToken(id) {
  54. return Jwt.token.generate({ id }, {
  55. key: this.options.jwtKey,
  56. algorithm: 'HS256'
  57. }, {
  58. ttlSec: 7 * 24 * 60 * 60 // 7 days
  59. })
  60. }
  61. async changePassword(id, password, txn) {
  62. const { User } = this.server.models()
  63. await User.query(txn).throwIfNotFound().where({ id }).patch({
  64. password: await this.pwd.hash(Buffer.from(password))
  65. })
  66. return id
  67. }
  68. }