From 9f901fb1babfbd72d8ef3a8493319d56d2e0a0bf Mon Sep 17 00:00:00 2001 From: Henry Oswald Date: Thu, 15 May 2014 17:16:20 +0100 Subject: [PATCH] added the token generator and its getNewToken function --- .../PasswordResetController.coffee | 9 ++-- .../PasswordReset/PasswordResetRouter.coffee | 4 +- .../PasswordReset/TokenGenerator.coffee | 20 ++++++++ services/web/app/views/user/setPassword.jade | 19 ++++++++ .../PasswordResetControllerTests.coffee | 4 +- .../PasswordReset/TokenGeneratorTests.coffee | 48 +++++++++++++++++++ 6 files changed, 96 insertions(+), 8 deletions(-) create mode 100644 services/web/app/coffee/Features/PasswordReset/TokenGenerator.coffee create mode 100644 services/web/app/views/user/setPassword.jade create mode 100644 services/web/test/UnitTests/coffee/PasswordReset/TokenGeneratorTests.coffee diff --git a/services/web/app/coffee/Features/PasswordReset/PasswordResetController.coffee b/services/web/app/coffee/Features/PasswordReset/PasswordResetController.coffee index 36173b4589..b30b3d01fe 100644 --- a/services/web/app/coffee/Features/PasswordReset/PasswordResetController.coffee +++ b/services/web/app/coffee/Features/PasswordReset/PasswordResetController.coffee @@ -14,17 +14,16 @@ module.exports = else res.send 200 - renderSetPasswordForm: (req, res)-> res.render "user/setPassword", title:"Set Password" - + passwordResetToken:req.query.passwordResetToken setNewUserPassword: (req, res)-> - {token, password} = req.body - if !password? or password.length < 4 or !token? or token.length == 0 + {passwordResetToken, password} = req.body + if !password? or password.length < 4 or !passwordResetToken? or passwordResetToken.length == 0 return res.send 500 - PasswordResetHandler.setNewUserPassword token?.trim(), password?.trim(), (err)-> + PasswordResetHandler.setNewUserPassword passwordResetToken?.trim(), password?.trim(), (err)-> if err? res.send 500 else diff --git a/services/web/app/coffee/Features/PasswordReset/PasswordResetRouter.coffee b/services/web/app/coffee/Features/PasswordReset/PasswordResetRouter.coffee index a40b2b5612..5a0afd9eef 100644 --- a/services/web/app/coffee/Features/PasswordReset/PasswordResetRouter.coffee +++ b/services/web/app/coffee/Features/PasswordReset/PasswordResetRouter.coffee @@ -1,8 +1,10 @@ +PasswordResetController = require("./PasswordResetController") + module.exports = apply: (app) -> app.get '/user/password/reset', PasswordResetController.renderRequestResetForm - app.post '/user/password/reset', ProjectDownloadsController.requestReset + app.post '/user/password/reset', PasswordResetController.requestReset app.get '/user/password/set', PasswordResetController.renderSetPasswordForm app.post '/user/password/set', PasswordResetController.setNewUserPassword diff --git a/services/web/app/coffee/Features/PasswordReset/TokenGenerator.coffee b/services/web/app/coffee/Features/PasswordReset/TokenGenerator.coffee new file mode 100644 index 0000000000..d20bfa8b80 --- /dev/null +++ b/services/web/app/coffee/Features/PasswordReset/TokenGenerator.coffee @@ -0,0 +1,20 @@ +Settings = require('settings-sharelatex') +redis = require('redis') +rclient = redis.createClient(Settings.redis.web.port, Settings.redis.web.host) +rclient.auth(Settings.redis.web.password) +uuid = require("node-uuid") + +ONE_MIN = 60 * 1000 +ONE_HOUR_IN_MS = ONE_MIN * 60 + +module.exports = + + getNewToken: (user_id, callback)-> + token = uuid.v4() + multi = rclient.multi() + multi.set token, user_id + multi.expire token, ONE_HOUR_IN_MS + multi.exec (err)-> + callback(err, token) + + getUserIdFromToken: (token, callback)-> diff --git a/services/web/app/views/user/setPassword.jade b/services/web/app/views/user/setPassword.jade new file mode 100644 index 0000000000..b07e18cebd --- /dev/null +++ b/services/web/app/views/user/setPassword.jade @@ -0,0 +1,19 @@ +extends ../layout + +block content + .container + .row + .box.span4.offset4 + .page-header + h1 Set Password + .messageArea + form.validate#passwordReset(method='post') + input(type="hidden", name="_csrf", value=csrfToken) + .clearfix + label(for='xlInput') Password + .input + input.span4.email.required(type='password', name='password', placeholder='password') + .input + input(type="hidden", name="passwordResetToken", value=passwordResetToken) + .actions + button.btn.btn-primary.btn.btn-large(type='submit') Submit \ No newline at end of file diff --git a/services/web/test/UnitTests/coffee/PasswordReset/PasswordResetControllerTests.coffee b/services/web/test/UnitTests/coffee/PasswordReset/PasswordResetControllerTests.coffee index be053afe38..26417906d8 100644 --- a/services/web/test/UnitTests/coffee/PasswordReset/PasswordResetControllerTests.coffee +++ b/services/web/test/UnitTests/coffee/PasswordReset/PasswordResetControllerTests.coffee @@ -25,7 +25,7 @@ describe "PasswordResetController", -> @req = body: email:@email - token:@token + passwordResetToken:@token password:@password @res ={} @@ -78,7 +78,7 @@ describe "PasswordResetController", -> it "should error if there is no password", (done)-> - @req.body.token = "" + @req.body.passwordResetToken = "" @PasswordResetHandler.setNewUserPassword.callsArgWith(2) @res.send = (code)=> code.should.equal 500 diff --git a/services/web/test/UnitTests/coffee/PasswordReset/TokenGeneratorTests.coffee b/services/web/test/UnitTests/coffee/PasswordReset/TokenGeneratorTests.coffee new file mode 100644 index 0000000000..7c4b263fa2 --- /dev/null +++ b/services/web/test/UnitTests/coffee/PasswordReset/TokenGeneratorTests.coffee @@ -0,0 +1,48 @@ +should = require('chai').should() +SandboxedModule = require('sandboxed-module') +assert = require('assert') +path = require('path') +sinon = require('sinon') +modulePath = path.join __dirname, "../../../../app/js/Features/PasswordReset/TokenGenerator" +expect = require("chai").expect + +describe "TokenGenerator", -> + + beforeEach -> + @user_id = "user id here" + @stubbedToken = "dsajdiojlklksda" + + @settings = + redis: + web:{} + @redisMulti = + set:sinon.stub() + expire:sinon.stub() + exec:sinon.stub() + @uuid = v4 : -> return @stubbedToken + self = @ + @TokenGenerator = SandboxedModule.require modulePath, requires: + "redis" : + createClient: => + auth:-> + multi: -> return self.redisMulti + + "settings-sharelatex":@settings + "logger-sharelatex": log:-> + "node-uuid":@uuid + + + describe "getNewToken", -> + + it "should set a new token into redis with a ttl", (done)-> + @redisMulti.exec.callsArgWith(0) + @TokenGenerator.getNewToken @user_id, (err, token)=> + @redisMulti.set @stubbedToken, @user_id + @redisMulti.expire @stubbedToken, (60*1000)*60 + done() + + it "should return if there was an error", (done)-> + @redisMulti.exec.callsArgWith(0, "error") + @TokenGenerator.getNewToken @user_id, (err, token)=> + err.should.exist + done()