AuthenticationManager.coffee 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. Settings = require "settings-sharelatex"
  2. User = require("../../models/User").User
  3. {db, ObjectId} = require("../../infrastructure/mongojs")
  4. crypto = require 'crypto'
  5. bcrypt = require 'bcrypt'
  6. EmailHelper = require("../Helpers/EmailHelper")
  7. Errors = require("../Errors/Errors")
  8. UserGetter = require("../User/UserGetter")
  9. V1Handler = require '../V1/V1Handler'
  10. BCRYPT_ROUNDS = Settings?.security?.bcryptRounds or 12
  11. _checkWriteResult = (result, callback = (error, updated) ->) ->
  12. # for MongoDB
  13. if result and result.nModified == 1
  14. callback(null, true)
  15. else
  16. callback(null, false)
  17. module.exports = AuthenticationManager =
  18. authenticate: (query, password, callback = (error, user) ->) ->
  19. # Using Mongoose for legacy reasons here. The returned User instance
  20. # gets serialized into the session and there may be subtle differences
  21. # between the user returned by Mongoose vs mongojs (such as default values)
  22. User.findOne query, (error, user) =>
  23. return callback(error) if error?
  24. if user?
  25. if user.hashedPassword?
  26. bcrypt.compare password, user.hashedPassword, (error, match) ->
  27. return callback(error) if error?
  28. if match
  29. AuthenticationManager.checkRounds user, user.hashedPassword, password, (err) ->
  30. return callback(err) if err?
  31. callback null, user
  32. else
  33. callback null, null
  34. else
  35. callback null, null
  36. else
  37. callback null, null
  38. validateEmail: (email) ->
  39. parsed = EmailHelper.parseEmail(email)
  40. if !parsed?
  41. return { message: 'email not valid' }
  42. return null
  43. validatePassword: (password) ->
  44. if !password?
  45. return { message: 'password not set' }
  46. if (Settings.passwordStrengthOptions?.length?.max? and
  47. password.length > Settings.passwordStrengthOptions?.length?.max)
  48. return { message: "password is too long" }
  49. if (Settings.passwordStrengthOptions?.length?.min? and
  50. password.length < Settings.passwordStrengthOptions?.length?.min)
  51. return { message: 'password is too short' }
  52. return null
  53. setUserPassword: (user_id, password, callback = (error, changed) ->) ->
  54. validation = @validatePassword(password)
  55. return callback(validation.message) if validation?
  56. UserGetter.getUser user_id, { email:1, overleaf: 1 }, (error, user) ->
  57. return callback(error) if error?
  58. v1IdExists = user.overleaf?.id?
  59. if v1IdExists and Settings.overleaf? # v2 user in v2
  60. # v2 user in v2, change password in v1
  61. AuthenticationManager.setUserPasswordInV1(user.overleaf.id, password, callback)
  62. else if v1IdExists and !Settings.overleaf?
  63. # v2 user in SL
  64. return callback(new Errors.NotInV2Error("Password Reset Attempt"))
  65. else if !v1IdExists and !Settings.overleaf?
  66. # SL user in SL, change password in SL
  67. AuthenticationManager.setUserPasswordInV2(user_id, password, callback)
  68. else if !v1IdExists and Settings.overleaf?
  69. # SL user in v2, should not happen
  70. return callback(new Errors.SLInV2Error("Password Reset Attempt"))
  71. else
  72. return callback(new Error("Password Reset Attempt Failed"))
  73. checkRounds: (user, hashedPassword, password, callback = (error) ->) ->
  74. # check current number of rounds and rehash if necessary
  75. currentRounds = bcrypt.getRounds hashedPassword
  76. if currentRounds < BCRYPT_ROUNDS
  77. AuthenticationManager.setUserPassword user._id, password, callback
  78. else
  79. callback()
  80. setUserPasswordInV2: (user_id, password, callback) ->
  81. validation = @validatePassword(password)
  82. return callback(validation.message) if validation?
  83. bcrypt.genSalt BCRYPT_ROUNDS, (error, salt) ->
  84. return callback(error) if error?
  85. bcrypt.hash password, salt, (error, hash) ->
  86. return callback(error) if error?
  87. db.users.update({
  88. _id: ObjectId(user_id.toString())
  89. }, {
  90. $set: hashedPassword: hash
  91. $unset: password: true
  92. }, (updateError, result)->
  93. return callback(updateError) if updateError?
  94. _checkWriteResult(result, callback)
  95. )
  96. setUserPasswordInV1: (v1_user_id, password, callback) ->
  97. validation = @validatePassword(password)
  98. return callback(validation.message) if validation?
  99. V1Handler.doPasswordReset v1_user_id, password, (error, reset)->
  100. return callback(error) if error?
  101. return callback(error, reset)