mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-07 20:31:06 -05:00
Add backend endpoint for resending confirmation email
This commit is contained in:
parent
67e2f6f942
commit
33b28db061
5 changed files with 154 additions and 9 deletions
|
@ -27,6 +27,16 @@ module.exports =
|
|||
return callback(error) if error?
|
||||
callback null, token
|
||||
|
||||
findValidTokenFromData: (use, data, callback = (error, token) ->) ->
|
||||
db.tokens.findOne {
|
||||
use: use,
|
||||
data: data,
|
||||
expiresAt: { $gt: new Date() },
|
||||
usedAt: { $exists: false }
|
||||
}, (error, token) ->
|
||||
return callback(error) if error?
|
||||
return callback null, token?.token
|
||||
|
||||
getValueFromTokenAndExpire: (use, token, callback = (error, data) ->)->
|
||||
logger.log token_start: token.slice(0,8), "getting data from #{use} token"
|
||||
now = new Date()
|
||||
|
|
|
@ -23,6 +23,17 @@ module.exports = UserEmailsConfirmationHandler =
|
|||
confirmEmailUrl: "#{settings.siteUrl}/user/emails/confirm?token=#{token}"
|
||||
EmailHandler.sendEmail emailTemplate, emailOptions, callback
|
||||
|
||||
resendConfirmationEmail: (user_id, email, callback = (error) ->) ->
|
||||
OneTimeTokenHandler.findValidTokenFromData 'email_confirmation', { user_id, email }, (error, token) ->
|
||||
return callback(error) if error?
|
||||
if !token?
|
||||
UserEmailsConfirmationHandler.sendConfirmationEmail user_id, email, callback
|
||||
else
|
||||
emailOptions =
|
||||
to: email
|
||||
confirmEmailUrl: "#{settings.siteUrl}/user/emails/confirm?token=#{token}"
|
||||
EmailHandler.sendEmail 'confirmEmail', emailOptions, callback
|
||||
|
||||
confirmEmailFromToken: (token, callback = (error) ->) ->
|
||||
logger.log {token_start: token.slice(0,8)}, 'confirming email from token'
|
||||
OneTimeTokenHandler.getValueFromTokenAndExpire 'email_confirmation', token, (error, data) ->
|
||||
|
|
|
@ -61,6 +61,19 @@ module.exports = UserEmailsController =
|
|||
return next(error) if error?
|
||||
res.sendStatus 204
|
||||
|
||||
resendConfirmation: (req, res, next) ->
|
||||
userId = AuthenticationController.getLoggedInUserId(req)
|
||||
email = EmailHelper.parseEmail(req.body.email)
|
||||
return res.sendStatus 422 unless email?
|
||||
UserGetter.getUserByAnyEmail email, {_id:1}, (error, user) ->
|
||||
return next(error) if error?
|
||||
if !user? or user?._id?.toString() != userId
|
||||
logger.log {userId, email, foundUserId: user?._id}, "email doesn't match logged in user"
|
||||
return res.sendStatus 422
|
||||
logger.log {userId, email}, 'resending email confirmation token'
|
||||
UserEmailsConfirmationHandler.resendConfirmationEmail userId, email, (error) ->
|
||||
return next(error) if error?
|
||||
res.sendStatus 200
|
||||
|
||||
showConfirm: (req, res, next) ->
|
||||
res.render 'user/confirm_email', {
|
||||
|
|
|
@ -115,6 +115,9 @@ module.exports = class Router
|
|||
UserEmailsController.showConfirm
|
||||
webRouter.post '/user/emails/confirm',
|
||||
UserEmailsController.confirm
|
||||
webRouter.post '/user/emails/resend_confirmation',
|
||||
AuthenticationController.requireLogin(),
|
||||
UserEmailsController.resendConfirmation
|
||||
|
||||
if Features.hasFeature 'affiliations'
|
||||
webRouter.post '/user/emails',
|
||||
|
|
|
@ -17,7 +17,7 @@ describe "UserEmails", ->
|
|||
token = null
|
||||
async.series [
|
||||
(cb) =>
|
||||
@user.request {
|
||||
@user.request {
|
||||
method: 'POST',
|
||||
url: '/user/emails',
|
||||
json:
|
||||
|
@ -45,7 +45,7 @@ describe "UserEmails", ->
|
|||
token = tokens[0].token
|
||||
cb()
|
||||
(cb) =>
|
||||
@user.request {
|
||||
@user.request {
|
||||
method: 'POST',
|
||||
url: '/user/emails/confirm',
|
||||
json:
|
||||
|
@ -80,7 +80,7 @@ describe "UserEmails", ->
|
|||
(cb) => @user2.login cb
|
||||
(cb) =>
|
||||
# Create email for first user
|
||||
@user.request {
|
||||
@user.request {
|
||||
method: 'POST',
|
||||
url: '/user/emails',
|
||||
json: {@email}
|
||||
|
@ -99,21 +99,21 @@ describe "UserEmails", ->
|
|||
cb()
|
||||
(cb) =>
|
||||
# Delete the email from the first user
|
||||
@user.request {
|
||||
@user.request {
|
||||
method: 'POST',
|
||||
url: '/user/emails/delete',
|
||||
json: {@email}
|
||||
}, cb
|
||||
(cb) =>
|
||||
# Create email for second user
|
||||
@user2.request {
|
||||
@user2.request {
|
||||
method: 'POST',
|
||||
url: '/user/emails',
|
||||
json: {@email}
|
||||
}, cb
|
||||
(cb) =>
|
||||
# Original confirmation token should no longer work
|
||||
@user.request {
|
||||
@user.request {
|
||||
method: 'POST',
|
||||
url: '/user/emails/confirm',
|
||||
json:
|
||||
|
@ -158,7 +158,7 @@ describe "UserEmails", ->
|
|||
token = null
|
||||
async.series [
|
||||
(cb) =>
|
||||
@user.request {
|
||||
@user.request {
|
||||
method: 'POST',
|
||||
url: '/user/emails',
|
||||
json:
|
||||
|
@ -183,12 +183,12 @@ describe "UserEmails", ->
|
|||
db.tokens.update {
|
||||
token: token
|
||||
}, {
|
||||
$set: {
|
||||
$set: {
|
||||
expiresAt: new Date(Date.now() - 1000000)
|
||||
}
|
||||
}, cb
|
||||
(cb) =>
|
||||
@user.request {
|
||||
@user.request {
|
||||
method: 'POST',
|
||||
url: '/user/emails/confirm',
|
||||
json:
|
||||
|
@ -198,3 +198,111 @@ describe "UserEmails", ->
|
|||
expect(response.statusCode).to.equal 404
|
||||
cb()
|
||||
], done
|
||||
|
||||
describe 'resending the confirmation', ->
|
||||
it 'should resend the existing token', (done) ->
|
||||
token = null
|
||||
async.series [
|
||||
(cb) =>
|
||||
@user.request {
|
||||
method: 'POST',
|
||||
url: '/user/emails',
|
||||
json:
|
||||
email: 'reconfirmation-email@example.com'
|
||||
}, (error, response, body) =>
|
||||
return done(error) if error?
|
||||
expect(response.statusCode).to.equal 204
|
||||
cb()
|
||||
(cb) =>
|
||||
db.tokens.find {
|
||||
use: 'email_confirmation',
|
||||
'data.user_id': @user._id,
|
||||
usedAt: { $exists: false }
|
||||
}, (error, tokens) =>
|
||||
# There should only be one confirmation token at the moment
|
||||
expect(tokens.length).to.equal 1
|
||||
expect(tokens[0].data.email).to.equal 'reconfirmation-email@example.com'
|
||||
expect(tokens[0].data.user_id).to.equal @user._id
|
||||
token = tokens[0].token
|
||||
cb()
|
||||
(cb) =>
|
||||
@user.request {
|
||||
method: 'POST',
|
||||
url: '/user/emails/resend_confirmation',
|
||||
json:
|
||||
email: 'reconfirmation-email@example.com'
|
||||
}, (error, response, body) =>
|
||||
return done(error) if error?
|
||||
expect(response.statusCode).to.equal 200
|
||||
cb()
|
||||
(cb) =>
|
||||
db.tokens.find {
|
||||
use: 'email_confirmation',
|
||||
'data.user_id': @user._id,
|
||||
usedAt: { $exists: false }
|
||||
}, (error, tokens) =>
|
||||
# There should still only be one confirmation token
|
||||
expect(tokens.length).to.equal 1
|
||||
expect(tokens[0].data.email).to.equal 'reconfirmation-email@example.com'
|
||||
expect(tokens[0].data.user_id).to.equal @user._id
|
||||
token = tokens[0].token
|
||||
cb()
|
||||
], done
|
||||
|
||||
it 'should create a new token if none exists', (done) ->
|
||||
# This should only be for users that have sign up with their main
|
||||
# emails before the confirmation system existed
|
||||
token = null
|
||||
async.series [
|
||||
(cb) =>
|
||||
db.tokens.remove {
|
||||
use: 'email_confirmation',
|
||||
'data.user_id': @user._id,
|
||||
usedAt: { $exists: false }
|
||||
}, cb
|
||||
(cb) =>
|
||||
@user.request {
|
||||
method: 'POST',
|
||||
url: '/user/emails/resend_confirmation',
|
||||
json:
|
||||
email: @user.email
|
||||
}, (error, response, body) =>
|
||||
return done(error) if error?
|
||||
expect(response.statusCode).to.equal 200
|
||||
cb()
|
||||
(cb) =>
|
||||
db.tokens.find {
|
||||
use: 'email_confirmation',
|
||||
'data.user_id': @user._id,
|
||||
usedAt: { $exists: false }
|
||||
}, (error, tokens) =>
|
||||
# There should still only be one confirmation token
|
||||
expect(tokens.length).to.equal 1
|
||||
expect(tokens[0].data.email).to.equal @user.email
|
||||
expect(tokens[0].data.user_id).to.equal @user._id
|
||||
token = tokens[0].token
|
||||
cb()
|
||||
], done
|
||||
|
||||
it "should not allow reconfirmation if the email doesn't match the user", (done) ->
|
||||
token = null
|
||||
async.series [
|
||||
(cb) =>
|
||||
@user.request {
|
||||
method: 'POST',
|
||||
url: '/user/emails/resend_confirmation',
|
||||
json:
|
||||
email: 'non-matching-email@example.com'
|
||||
}, (error, response, body) =>
|
||||
return done(error) if error?
|
||||
expect(response.statusCode).to.equal 422
|
||||
cb()
|
||||
(cb) =>
|
||||
db.tokens.find {
|
||||
use: 'email_confirmation',
|
||||
'data.user_id': @user._id,
|
||||
usedAt: { $exists: false }
|
||||
}, (error, tokens) =>
|
||||
expect(tokens.length).to.equal 0
|
||||
cb()
|
||||
], done
|
||||
|
|
Loading…
Reference in a new issue