make PasswordResetTokenHandler generic so it can be used for invites

This commit is contained in:
Henry Oswald 2015-05-26 15:24:09 +01:00
parent 12bf268978
commit 841231dbf8
8 changed files with 40 additions and 40 deletions

View file

@ -299,7 +299,7 @@ module.exports = (grunt) ->
settings = require "settings-sharelatex" settings = require "settings-sharelatex"
UserRegistrationHandler = require "./app/js/Features/User/UserRegistrationHandler" UserRegistrationHandler = require "./app/js/Features/User/UserRegistrationHandler"
PasswordResetTokenHandler = require "./app/js/Features/PasswordReset/PasswordResetTokenHandler" OneTimeTokenHandler = require "./app/js/Features/Security/OneTimeTokenHandler"
UserRegistrationHandler.registerNewUser { UserRegistrationHandler.registerNewUser {
email: email email: email
password: require("crypto").randomBytes(32).toString("hex") password: require("crypto").randomBytes(32).toString("hex")
@ -310,7 +310,7 @@ module.exports = (grunt) ->
user.save (error) -> user.save (error) ->
throw error if error? throw error if error?
ONE_WEEK = 7 * 24 * 60 * 60 # seconds ONE_WEEK = 7 * 24 * 60 * 60 # seconds
PasswordResetTokenHandler.getNewToken user._id, { expiresIn: ONE_WEEK }, (err, token)-> OneTimeTokenHandler.getNewToken user._id, { expiresIn: ONE_WEEK }, (err, token)->
return next(err) if err? return next(err) if err?
console.log "" console.log ""

View file

@ -1,7 +1,7 @@
settings = require("settings-sharelatex") settings = require("settings-sharelatex")
async = require("async") async = require("async")
UserGetter = require("../User/UserGetter") UserGetter = require("../User/UserGetter")
PasswordResetTokenHandler = require("./PasswordResetTokenHandler") OneTimeTokenHandler = require("./OneTimeTokenHandler")
EmailHandler = require("../Email/EmailHandler") EmailHandler = require("../Email/EmailHandler")
AuthenticationManager = require("../Authentication/AuthenticationManager") AuthenticationManager = require("../Authentication/AuthenticationManager")
logger = require("logger-sharelatex") logger = require("logger-sharelatex")
@ -14,7 +14,7 @@ module.exports =
if !user? or user.holdingAccount if !user? or user.holdingAccount
logger.err email:email, "user could not be found for password reset" logger.err email:email, "user could not be found for password reset"
return callback(null, false) return callback(null, false)
PasswordResetTokenHandler.getNewToken user._id, (err, token)-> OneTimeTokenHandler.getNewToken user._id, (err, token)->
if err then return callback(err) if err then return callback(err)
emailOptions = emailOptions =
to : email to : email
@ -24,7 +24,7 @@ module.exports =
callback null, true callback null, true
setNewUserPassword: (token, password, callback = (error, found) ->)-> setNewUserPassword: (token, password, callback = (error, found) ->)->
PasswordResetTokenHandler.getUserIdFromTokenAndExpire token, (err, user_id)-> OneTimeTokenHandler.getValueFromTokenAndExpire token, (err, user_id)->
if err then return callback(err) if err then return callback(err)
if !user_id? if !user_id?
return callback null, false return callback null, false

View file

@ -10,21 +10,21 @@ buildKey = (token)-> return "password_token:#{token}"
module.exports = module.exports =
getNewToken: (user_id, options = {}, callback)-> getNewToken: (value, options = {}, callback)->
# options is optional # options is optional
if typeof options == "function" if typeof options == "function"
callback = options callback = options
options = {} options = {}
expiresIn = options.expiresIn or ONE_HOUR_IN_S expiresIn = options.expiresIn or ONE_HOUR_IN_S
logger.log user_id:user_id, "generating token for password reset" logger.log value:value, "generating token for password reset"
token = crypto.randomBytes(32).toString("hex") token = crypto.randomBytes(32).toString("hex")
multi = rclient.multi() multi = rclient.multi()
multi.set buildKey(token), user_id multi.set buildKey(token), value
multi.expire buildKey(token), expiresIn multi.expire buildKey(token), expiresIn
multi.exec (err)-> multi.exec (err)->
callback(err, token) callback(err, token)
getUserIdFromTokenAndExpire: (token, callback)-> getValueFromTokenAndExpire: (token, callback)->
logger.log token:token, "getting user id from password token" logger.log token:token, "getting user id from password token"
multi = rclient.multi() multi = rclient.multi()
multi.get buildKey(token) multi.get buildKey(token)

View file

@ -3,7 +3,7 @@ logger = require("logger-sharelatex")
SubscriptionLocator = require("./SubscriptionLocator") SubscriptionLocator = require("./SubscriptionLocator")
settings = require("settings-sharelatex") settings = require("settings-sharelatex")
PasswordResetTokenHandler = require("../PasswordReset/PasswordResetTokenHandler") OneTimeTokenHandler = require("../Security/OneTimeTokenHandler")
EmailHandler = require("../Email/EmailHandler") EmailHandler = require("../Email/EmailHandler")
SubscriptionDomainAllocator = require("./SubscriptionDomainAllocator") SubscriptionDomainAllocator = require("./SubscriptionDomainAllocator")
@ -53,7 +53,7 @@ module.exports =
licence = SubscriptionDomainAllocator.findDomainLicenceBySubscriptionId(subscription_id) licence = SubscriptionDomainAllocator.findDomainLicenceBySubscriptionId(subscription_id)
if !licence? if !licence?
res.send 500 res.send 500
PasswordResetTokenHandler.getNewToken subscription_id, (err, token)-> OneTimeTokenHandler.getNewToken subscription_id, (err, token)->
opts = opts =
to : req.session.user.email to : req.session.user.email
group_name: licence.name group_name: licence.name
@ -63,9 +63,9 @@ module.exports =
completeJoin: (req, res)-> completeJoin: (req, res)->
subscription_id = req.params.subscription_id subscription_id = req.params.subscription_id
PasswordResetTokenHandler.getUserIdFromTokenAndExpire req.query.token, (err, token_subscription_id)-> OneTimeTokenHandler.getValueFromTokenAndExpire req.query.token, (err, token_subscription_id)->
console.log token_subscription_id console.log token_subscription_id
if subscription_id != token_subscription_id if err? or subscription_id != token_subscription_id
return res.send 403 return res.send 403
SubscriptionLocator.getSubscription subscription_id, (err, subscription)-> SubscriptionLocator.getSubscription subscription_id, (err, subscription)->
SubscriptionGroupHandler.addUserToGroup subscription.admin_id, req.user.email, (err, user)-> SubscriptionGroupHandler.addUserToGroup subscription.admin_id, req.user.email, (err, user)->

View file

@ -10,7 +10,7 @@ AuthenticationManager = require("../Authentication/AuthenticationManager")
UserUpdater = require("./UserUpdater") UserUpdater = require("./UserUpdater")
SubscriptionDomainAllocator = require("../Subscription/SubscriptionDomainAllocator") SubscriptionDomainAllocator = require("../Subscription/SubscriptionDomainAllocator")
EmailHandler = require("../Email/EmailHandler") EmailHandler = require("../Email/EmailHandler")
PasswordResetTokenHandler = require "../PasswordReset/PasswordResetTokenHandler" OneTimeTokenHandler = require "../Security/OneTimeTokenHandler"
settings = require "settings-sharelatex" settings = require "settings-sharelatex"
crypto = require "crypto" crypto = require "crypto"
@ -98,7 +98,7 @@ module.exports =
logger.log {email}, "user already exists, resending welcome email" logger.log {email}, "user already exists, resending welcome email"
ONE_WEEK = 7 * 24 * 60 * 60 # seconds ONE_WEEK = 7 * 24 * 60 * 60 # seconds
PasswordResetTokenHandler.getNewToken user._id, { expiresIn: ONE_WEEK }, (err, token)-> OneTimeTokenHandler.getNewToken user._id, { expiresIn: ONE_WEEK }, (err, token)->
return next(err) if err? return next(err) if err?
setNewPasswordUrl = "#{settings.siteUrl}/user/password/set?passwordResetToken=#{token}&email=#{encodeURIComponent(email)}" setNewPasswordUrl = "#{settings.siteUrl}/user/password/set?passwordResetToken=#{token}&email=#{encodeURIComponent(email)}"

View file

@ -12,9 +12,9 @@ describe "PasswordResetHandler", ->
@settings = @settings =
siteUrl: "www.sharelatex.com" siteUrl: "www.sharelatex.com"
@PasswordResetTokenHandler = @OneTimeTokenHandler =
getNewToken:sinon.stub() getNewToken:sinon.stub()
getUserIdFromTokenAndExpire:sinon.stub() getValueFromTokenAndExpire:sinon.stub()
@UserGetter = @UserGetter =
getUser:sinon.stub() getUser:sinon.stub()
@EmailHandler = @EmailHandler =
@ -23,7 +23,7 @@ describe "PasswordResetHandler", ->
setUserPassword:sinon.stub() setUserPassword:sinon.stub()
@PasswordResetHandler = SandboxedModule.require modulePath, requires: @PasswordResetHandler = SandboxedModule.require modulePath, requires:
"../User/UserGetter": @UserGetter "../User/UserGetter": @UserGetter
"./PasswordResetTokenHandler": @PasswordResetTokenHandler "./OneTimeTokenHandler": @OneTimeTokenHandler
"../Email/EmailHandler":@EmailHandler "../Email/EmailHandler":@EmailHandler
"../Authentication/AuthenticationManager":@AuthenticationManager "../Authentication/AuthenticationManager":@AuthenticationManager
"settings-sharelatex": @settings "settings-sharelatex": @settings
@ -41,7 +41,7 @@ describe "PasswordResetHandler", ->
it "should check the user exists", (done)-> it "should check the user exists", (done)->
@UserGetter.getUser.callsArgWith(1) @UserGetter.getUser.callsArgWith(1)
@PasswordResetTokenHandler.getNewToken.callsArgWith(1) @OneTimeTokenHandler.getNewToken.callsArgWith(1)
@PasswordResetHandler.generateAndEmailResetToken @user.email, (err, exists)=> @PasswordResetHandler.generateAndEmailResetToken @user.email, (err, exists)=>
exists.should.equal false exists.should.equal false
done() done()
@ -50,7 +50,7 @@ describe "PasswordResetHandler", ->
it "should send the email with the token", (done)-> it "should send the email with the token", (done)->
@UserGetter.getUser.callsArgWith(1, null, @user) @UserGetter.getUser.callsArgWith(1, null, @user)
@PasswordResetTokenHandler.getNewToken.callsArgWith(1, null, @token) @OneTimeTokenHandler.getNewToken.callsArgWith(1, null, @token)
@EmailHandler.sendEmail.callsArgWith(2) @EmailHandler.sendEmail.callsArgWith(2)
@PasswordResetHandler.generateAndEmailResetToken @user.email, (err, exists)=> @PasswordResetHandler.generateAndEmailResetToken @user.email, (err, exists)=>
@EmailHandler.sendEmail.called.should.equal true @EmailHandler.sendEmail.called.should.equal true
@ -63,7 +63,7 @@ describe "PasswordResetHandler", ->
it "should return exists = false for a holdingAccount", (done) -> it "should return exists = false for a holdingAccount", (done) ->
@user.holdingAccount = true @user.holdingAccount = true
@UserGetter.getUser.callsArgWith(1, null, @user) @UserGetter.getUser.callsArgWith(1, null, @user)
@PasswordResetTokenHandler.getNewToken.callsArgWith(1) @OneTimeTokenHandler.getNewToken.callsArgWith(1)
@PasswordResetHandler.generateAndEmailResetToken @user.email, (err, exists)=> @PasswordResetHandler.generateAndEmailResetToken @user.email, (err, exists)=>
exists.should.equal false exists.should.equal false
done() done()
@ -71,14 +71,14 @@ describe "PasswordResetHandler", ->
describe "setNewUserPassword", -> describe "setNewUserPassword", ->
it "should return false if no user id can be found", (done)-> it "should return false if no user id can be found", (done)->
@PasswordResetTokenHandler.getUserIdFromTokenAndExpire.callsArgWith(1) @OneTimeTokenHandler.getValueFromTokenAndExpire.callsArgWith(1)
@PasswordResetHandler.setNewUserPassword @token, @password, (err, found) => @PasswordResetHandler.setNewUserPassword @token, @password, (err, found) =>
found.should.equal false found.should.equal false
@AuthenticationManager.setUserPassword.called.should.equal false @AuthenticationManager.setUserPassword.called.should.equal false
done() done()
it "should set the user password", (done)-> it "should set the user password", (done)->
@PasswordResetTokenHandler.getUserIdFromTokenAndExpire.callsArgWith(1, null, @user_id) @OneTimeTokenHandler.getValueFromTokenAndExpire.callsArgWith(1, null, @user_id)
@AuthenticationManager.setUserPassword.callsArgWith(2) @AuthenticationManager.setUserPassword.callsArgWith(2)
@PasswordResetHandler.setNewUserPassword @token, @password, (err, found) => @PasswordResetHandler.setNewUserPassword @token, @password, (err, found) =>
found.should.equal true found.should.equal true

View file

@ -3,13 +3,13 @@ SandboxedModule = require('sandboxed-module')
assert = require('assert') assert = require('assert')
path = require('path') path = require('path')
sinon = require('sinon') sinon = require('sinon')
modulePath = path.join __dirname, "../../../../app/js/Features/PasswordReset/PasswordResetTokenHandler" modulePath = path.join __dirname, "../../../../app/js/Features/Security/OneTimeTokenHandler"
expect = require("chai").expect expect = require("chai").expect
describe "PasswordResetTokenHandler", -> describe "OneTimeTokenHandler", ->
beforeEach -> beforeEach ->
@user_id = "user id here" @value = "user id here"
@stubbedToken = require("crypto").randomBytes(32) @stubbedToken = require("crypto").randomBytes(32)
@settings = @settings =
@ -22,7 +22,7 @@ describe "PasswordResetTokenHandler", ->
expire:sinon.stub() expire:sinon.stub()
exec:sinon.stub() exec:sinon.stub()
self = @ self = @
@PasswordResetTokenHandler = SandboxedModule.require modulePath, requires: @OneTimeTokenHandler = SandboxedModule.require modulePath, requires:
"redis-sharelatex" : "redis-sharelatex" :
createClient: => createClient: =>
auth:-> auth:->
@ -37,30 +37,30 @@ describe "PasswordResetTokenHandler", ->
it "should set a new token into redis with a ttl", (done)-> it "should set a new token into redis with a ttl", (done)->
@redisMulti.exec.callsArgWith(0) @redisMulti.exec.callsArgWith(0)
@PasswordResetTokenHandler.getNewToken @user_id, (err, token) => @OneTimeTokenHandler.getNewToken @value, (err, token) =>
@redisMulti.set.calledWith("password_token:#{@stubbedToken.toString("hex")}", @user_id).should.equal true @redisMulti.set.calledWith("password_token:#{@stubbedToken.toString("hex")}", @value).should.equal true
@redisMulti.expire.calledWith("password_token:#{@stubbedToken.toString("hex")}", 60 * 60).should.equal true @redisMulti.expire.calledWith("password_token:#{@stubbedToken.toString("hex")}", 60 * 60).should.equal true
done() done()
it "should return if there was an error", (done)-> it "should return if there was an error", (done)->
@redisMulti.exec.callsArgWith(0, "error") @redisMulti.exec.callsArgWith(0, "error")
@PasswordResetTokenHandler.getNewToken @user_id, (err, token)=> @OneTimeTokenHandler.getNewToken @value, (err, token)=>
err.should.exist err.should.exist
done() done()
it "should allow the expiry time to be overridden", (done) -> it "should allow the expiry time to be overridden", (done) ->
@redisMulti.exec.callsArgWith(0) @redisMulti.exec.callsArgWith(0)
@ttl = 42 @ttl = 42
@PasswordResetTokenHandler.getNewToken @user_id, {expiresIn: @ttl}, (err, token) => @OneTimeTokenHandler.getNewToken @value, {expiresIn: @ttl}, (err, token) =>
@redisMulti.expire.calledWith("password_token:#{@stubbedToken.toString("hex")}", @ttl).should.equal true @redisMulti.expire.calledWith("password_token:#{@stubbedToken.toString("hex")}", @ttl).should.equal true
done() done()
describe "getUserIdFromTokenAndExpire", -> describe "getValueFromTokenAndExpire", ->
it "should get and delete the token", (done)-> it "should get and delete the token", (done)->
@redisMulti.exec.callsArgWith(0, null, [@user_id]) @redisMulti.exec.callsArgWith(0, null, [@value])
@PasswordResetTokenHandler.getUserIdFromTokenAndExpire @stubbedToken, (err, user_id)=> @OneTimeTokenHandler.getValueFromTokenAndExpire @stubbedToken, (err, value)=>
user_id.should.equal @user_id value.should.equal @value
@redisMulti.get.calledWith("password_token:#{@stubbedToken}").should.equal true @redisMulti.get.calledWith("password_token:#{@stubbedToken}").should.equal true
@redisMulti.del.calledWith("password_token:#{@stubbedToken}").should.equal true @redisMulti.del.calledWith("password_token:#{@stubbedToken}").should.equal true
done() done()

View file

@ -42,7 +42,7 @@ describe "UserController", ->
changeEmailAddress:sinon.stub() changeEmailAddress:sinon.stub()
@EmailHandler = @EmailHandler =
sendEmail:sinon.stub().callsArgWith(2) sendEmail:sinon.stub().callsArgWith(2)
@PasswordResetTokenHandler = @OneTimeTokenHandler =
getNewToken: sinon.stub() getNewToken: sinon.stub()
@settings = @settings =
siteUrl: "sharelatex.example.com" siteUrl: "sharelatex.example.com"
@ -58,7 +58,7 @@ describe "UserController", ->
"../Referal/ReferalAllocator":@ReferalAllocator "../Referal/ReferalAllocator":@ReferalAllocator
"../Subscription/SubscriptionDomainAllocator":@SubscriptionDomainAllocator "../Subscription/SubscriptionDomainAllocator":@SubscriptionDomainAllocator
"../Email/EmailHandler": @EmailHandler "../Email/EmailHandler": @EmailHandler
"../PasswordReset/PasswordResetTokenHandler": @PasswordResetTokenHandler "../Security/OneTimeTokenHandler": @OneTimeTokenHandler
"crypto": @crypto = {} "crypto": @crypto = {}
"settings-sharelatex": @settings "settings-sharelatex": @settings
"logger-sharelatex": {log:->} "logger-sharelatex": {log:->}
@ -177,7 +177,7 @@ describe "UserController", ->
beforeEach -> beforeEach ->
@req.body.email = @user.email = "email@example.com" @req.body.email = @user.email = "email@example.com"
@crypto.randomBytes = sinon.stub().returns({toString: () => @password = "mock-password"}) @crypto.randomBytes = sinon.stub().returns({toString: () => @password = "mock-password"})
@PasswordResetTokenHandler.getNewToken.callsArgWith(2, null, @token = "mock-token") @OneTimeTokenHandler.getNewToken.callsArgWith(2, null, @token = "mock-token")
describe "with a new user", -> describe "with a new user", ->
beforeEach -> beforeEach ->
@ -192,7 +192,7 @@ describe "UserController", ->
}).should.equal true }).should.equal true
it "should generate a new password reset token", -> it "should generate a new password reset token", ->
@PasswordResetTokenHandler.getNewToken @OneTimeTokenHandler.getNewToken
.calledWith(@user_id, expiresIn: 7 * 24 * 60 * 60) .calledWith(@user_id, expiresIn: 7 * 24 * 60 * 60)
.should.equal true .should.equal true
@ -218,7 +218,7 @@ describe "UserController", ->
@UserController.register @req, @res @UserController.register @req, @res
it "should still generate a new password token and email", -> it "should still generate a new password token and email", ->
@PasswordResetTokenHandler.getNewToken.called.should.equal true @OneTimeTokenHandler.getNewToken.called.should.equal true
@EmailHandler.sendEmail.called.should.equal true @EmailHandler.sendEmail.called.should.equal true
describe "changePassword", -> describe "changePassword", ->