mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-07 20:31:06 -05:00
Prevent registration of new accounts with existing secondary emails (#1696)
Prevent registration of new accounts with existing secondary emails GitOrigin-RevId: 004cf9d31064fc5b7deb621c95c38f103397ff15
This commit is contained in:
parent
f583ffdbff
commit
5b7974065d
4 changed files with 64 additions and 28 deletions
|
@ -24,11 +24,13 @@ module.exports =
|
|||
RateLimiter.addCount opts, (err, canContinue)->
|
||||
if !canContinue
|
||||
return res.send 429, { message: req.i18n.translate("rate_limit_hit_wait")}
|
||||
PasswordResetHandler.generateAndEmailResetToken email, (err, exists)->
|
||||
PasswordResetHandler.generateAndEmailResetToken email, (err, status)->
|
||||
if err?
|
||||
res.send 500, {message:err?.message}
|
||||
else if exists
|
||||
else if status == 'primary'
|
||||
res.send 200, {message: {text: req.i18n.translate("password_reset_email_sent")}}
|
||||
else if status == 'secondary'
|
||||
res.send 404, {message: req.i18n.translate("secondary_email_password_reset")}
|
||||
else
|
||||
res.send 404, {message: req.i18n.translate("cant_find_email")}
|
||||
|
||||
|
|
|
@ -9,10 +9,11 @@ V1Api = require("../V1/V1Api")
|
|||
|
||||
module.exports = PasswordResetHandler =
|
||||
|
||||
generateAndEmailResetToken:(email, callback = (error, exists) ->)->
|
||||
generateAndEmailResetToken:(email, callback = (error, status) ->)->
|
||||
PasswordResetHandler._getPasswordResetData email, (error, exists, data) ->
|
||||
if error? or !exists
|
||||
return callback(error, exists)
|
||||
if error?
|
||||
return callback(error, null)
|
||||
else if exists
|
||||
OneTimeTokenHandler.getNewToken 'password', data, (err, token)->
|
||||
if err then return callback(err)
|
||||
emailOptions =
|
||||
|
@ -20,7 +21,13 @@ module.exports = PasswordResetHandler =
|
|||
setNewPasswordUrl : "#{settings.siteUrl}/user/password/set?passwordResetToken=#{token}&email=#{encodeURIComponent(email)}"
|
||||
EmailHandler.sendEmail "passwordResetRequested", emailOptions, (error) ->
|
||||
return callback(error) if error?
|
||||
callback null, true
|
||||
callback null, 'primary'
|
||||
else
|
||||
UserGetter.getUserByAnyEmail email, (err, user) ->
|
||||
if !user
|
||||
return callback(error, null)
|
||||
else
|
||||
return callback(error, 'secondary')
|
||||
|
||||
setNewUserPassword: (token, password, callback = (error, found, user_id) ->)->
|
||||
OneTimeTokenHandler.getValueFromTokenAndExpire 'password', token, (err, data)->
|
||||
|
|
|
@ -54,7 +54,7 @@ describe "PasswordResetController", ->
|
|||
describe "requestReset", ->
|
||||
|
||||
it "should error if the rate limit is hit", (done)->
|
||||
@PasswordResetHandler.generateAndEmailResetToken.callsArgWith(1, null, true)
|
||||
@PasswordResetHandler.generateAndEmailResetToken.callsArgWith(1, null, 'primary')
|
||||
@RateLimiter.addCount.callsArgWith(1, null, false)
|
||||
@res.send = (code)=>
|
||||
code.should.equal 429
|
||||
|
@ -65,7 +65,7 @@ describe "PasswordResetController", ->
|
|||
|
||||
it "should tell the handler to process that email", (done)->
|
||||
@RateLimiter.addCount.callsArgWith(1, null, true)
|
||||
@PasswordResetHandler.generateAndEmailResetToken.callsArgWith(1, null, true)
|
||||
@PasswordResetHandler.generateAndEmailResetToken.callsArgWith(1, null, 'primary')
|
||||
@res.send = (code)=>
|
||||
code.should.equal 200
|
||||
@PasswordResetHandler.generateAndEmailResetToken.calledWith(@email.trim()).should.equal true
|
||||
|
@ -82,7 +82,15 @@ describe "PasswordResetController", ->
|
|||
|
||||
it "should send a 404 if the email doesn't exist", (done)->
|
||||
@RateLimiter.addCount.callsArgWith(1, null, true)
|
||||
@PasswordResetHandler.generateAndEmailResetToken.callsArgWith(1, null, false)
|
||||
@PasswordResetHandler.generateAndEmailResetToken.callsArgWith(1, null, null)
|
||||
@res.send = (code)=>
|
||||
code.should.equal 404
|
||||
done()
|
||||
@PasswordResetController.requestReset @req, @res
|
||||
|
||||
it "should send a 404 if the email is registered as a secondard email", (done)->
|
||||
@RateLimiter.addCount.callsArgWith(1, null, true)
|
||||
@PasswordResetHandler.generateAndEmailResetToken.callsArgWith(1, null, 'secondary')
|
||||
@res.send = (code)=>
|
||||
code.should.equal 404
|
||||
done()
|
||||
|
@ -92,7 +100,7 @@ describe "PasswordResetController", ->
|
|||
@email = "UPerCaseEMAIL@example.Com"
|
||||
@req.body.email = @email
|
||||
@RateLimiter.addCount.callsArgWith(1, null, true)
|
||||
@PasswordResetHandler.generateAndEmailResetToken.callsArgWith(1, null, true)
|
||||
@PasswordResetHandler.generateAndEmailResetToken.callsArgWith(1, null, 'primary')
|
||||
@res.send = (code)=>
|
||||
code.should.equal 200
|
||||
@PasswordResetHandler.generateAndEmailResetToken.calledWith(@email.toLowerCase()).should.equal true
|
||||
|
|
|
@ -18,6 +18,7 @@ describe "PasswordResetHandler", ->
|
|||
@UserGetter =
|
||||
getUserByMainEmail:sinon.stub()
|
||||
getUser: sinon.stub()
|
||||
getUserByAnyEmail: sinon.stub()
|
||||
@EmailHandler =
|
||||
sendEmail:sinon.stub()
|
||||
@AuthenticationManager =
|
||||
|
@ -48,29 +49,31 @@ describe "PasswordResetHandler", ->
|
|||
describe "when in ShareLaTeX", ->
|
||||
it "should check the user exists", (done)->
|
||||
@UserGetter.getUserByMainEmail.callsArgWith(1)
|
||||
@UserGetter.getUserByAnyEmail.callsArgWith(1)
|
||||
@OneTimeTokenHandler.getNewToken.yields()
|
||||
@PasswordResetHandler.generateAndEmailResetToken @user.email, (err, exists)=>
|
||||
exists.should.equal false
|
||||
@PasswordResetHandler.generateAndEmailResetToken @user.email, (err, status)=>
|
||||
should.equal(status, null)
|
||||
done()
|
||||
|
||||
it "should send the email with the token", (done)->
|
||||
@UserGetter.getUserByMainEmail.callsArgWith(1, null, @user)
|
||||
@OneTimeTokenHandler.getNewToken.yields(null, @token)
|
||||
@EmailHandler.sendEmail.callsArgWith(2)
|
||||
@PasswordResetHandler.generateAndEmailResetToken @user.email, (err, exists)=>
|
||||
@PasswordResetHandler.generateAndEmailResetToken @user.email, (err, status)=>
|
||||
@EmailHandler.sendEmail.called.should.equal true
|
||||
exists.should.equal true
|
||||
status.should.equal 'primary'
|
||||
args = @EmailHandler.sendEmail.args[0]
|
||||
args[0].should.equal "passwordResetRequested"
|
||||
args[1].setNewPasswordUrl.should.equal "#{@settings.siteUrl}/user/password/set?passwordResetToken=#{@token}&email=#{encodeURIComponent(@user.email)}"
|
||||
done()
|
||||
|
||||
it "should return exists = false for a holdingAccount", (done) ->
|
||||
it "should return exists == null for a holdingAccount", (done) ->
|
||||
@user.holdingAccount = true
|
||||
@UserGetter.getUserByMainEmail.callsArgWith(1, null, @user)
|
||||
@UserGetter.getUserByAnyEmail.callsArgWith(1)
|
||||
@OneTimeTokenHandler.getNewToken.yields()
|
||||
@PasswordResetHandler.generateAndEmailResetToken @user.email, (err, exists)=>
|
||||
exists.should.equal false
|
||||
@PasswordResetHandler.generateAndEmailResetToken @user.email, (err, status)=>
|
||||
should.equal(status, null)
|
||||
done()
|
||||
|
||||
describe "when in overleaf", ->
|
||||
|
@ -105,12 +108,13 @@ describe "PasswordResetHandler", ->
|
|||
args[0].should.equal "passwordResetRequested"
|
||||
args[1].setNewPasswordUrl.should.equal "#{@settings.siteUrl}/user/password/set?passwordResetToken=#{@token}&email=#{encodeURIComponent(@user.email)}"
|
||||
|
||||
it 'should return exists == true', ->
|
||||
@callback.calledWith(null, true).should.equal true
|
||||
it 'should return status == true', ->
|
||||
@callback.calledWith(null, 'primary').should.equal true
|
||||
|
||||
describe "when the email doesn't exist", ->
|
||||
beforeEach ->
|
||||
@V1Api.request = sinon.stub().yields(null, { statusCode: 404 }, {})
|
||||
@UserGetter.getUserByAnyEmail.callsArgWith(1)
|
||||
@PasswordResetHandler.generateAndEmailResetToken @email, @callback
|
||||
|
||||
it 'should not set the password token data', ->
|
||||
|
@ -120,9 +124,24 @@ describe "PasswordResetHandler", ->
|
|||
it 'should send an email with the token', ->
|
||||
@EmailHandler.sendEmail.called.should.equal false
|
||||
|
||||
it 'should return exists == false', ->
|
||||
@callback.calledWith(null, false).should.equal true
|
||||
it 'should return status == null', ->
|
||||
@callback.calledWith(null, null).should.equal true
|
||||
|
||||
describe "when the email is a secondary email", ->
|
||||
beforeEach ->
|
||||
@V1Api.request = sinon.stub().yields(null, { statusCode: 404 }, {})
|
||||
@UserGetter.getUserByAnyEmail.callsArgWith(1, null, @user)
|
||||
@PasswordResetHandler.generateAndEmailResetToken @email, @callback
|
||||
|
||||
it 'should not set the password token data', ->
|
||||
@OneTimeTokenHandler.getNewToken
|
||||
.called.should.equal false
|
||||
|
||||
it 'should not send an email with the token', ->
|
||||
@EmailHandler.sendEmail.called.should.equal false
|
||||
|
||||
it 'should return status == secondary', ->
|
||||
@callback.calledWith(null, 'secondary').should.equal true
|
||||
|
||||
describe "setNewUserPassword", ->
|
||||
describe "when no data is found", ->
|
||||
|
|
Loading…
Reference in a new issue