mirror of
https://github.com/overleaf/overleaf.git
synced 2025-04-10 01:46:43 +00:00
Merge pull request #1383 from sharelatex/spd-rate-limits
Add rate limits to email-related endpoints GitOrigin-RevId: 05a8b40eb65a55aba35788e2401e6988b672b389
This commit is contained in:
parent
eb5738886a
commit
4360a55fdc
8 changed files with 46 additions and 11 deletions
|
@ -101,11 +101,15 @@ module.exports = CollaboratorsInviteController =
|
|||
inviteId = req.params.invite_id
|
||||
logger.log {projectId, inviteId}, "resending invite"
|
||||
sendingUser = AuthenticationController.getSessionUser(req)
|
||||
CollaboratorsInviteHandler.resendInvite projectId, sendingUser, inviteId, (err) ->
|
||||
if err?
|
||||
logger.err {projectId, inviteId}, "error resending invite"
|
||||
return next(err)
|
||||
res.sendStatus(201)
|
||||
CollaboratorsInviteController._checkRateLimit sendingUser._id, (error, underRateLimit) ->
|
||||
return next(error) if error?
|
||||
if !underRateLimit
|
||||
return res.sendStatus(429)
|
||||
CollaboratorsInviteHandler.resendInvite projectId, sendingUser, inviteId, (err) ->
|
||||
if err?
|
||||
logger.err {projectId, inviteId}, "error resending invite"
|
||||
return next(err)
|
||||
res.sendStatus(201)
|
||||
|
||||
viewInvite: (req, res, next) ->
|
||||
projectId = req.params.Project_id
|
||||
|
|
|
@ -21,7 +21,7 @@ module.exports =
|
|||
throttle: 6
|
||||
RateLimiter.addCount opts, (err, canContinue)->
|
||||
if !canContinue
|
||||
return res.send 500, { message: req.i18n.translate("rate_limit_hit_wait")}
|
||||
return res.send 429, { message: req.i18n.translate("rate_limit_hit_wait")}
|
||||
PasswordResetHandler.generateAndEmailResetToken email, (err, exists)->
|
||||
if err?
|
||||
res.send 500, {message:err?.message}
|
||||
|
|
|
@ -3,6 +3,7 @@ SubscriptionController = require('./SubscriptionController')
|
|||
SubscriptionGroupController = require './SubscriptionGroupController'
|
||||
DomainLicenceController = require './DomainLicenceController'
|
||||
TeamInvitesController = require './TeamInvitesController'
|
||||
RateLimiterMiddlewear = require('../Security/RateLimiterMiddlewear')
|
||||
Settings = require "settings-sharelatex"
|
||||
|
||||
module.exports =
|
||||
|
@ -24,12 +25,25 @@ module.exports =
|
|||
# Team invites
|
||||
webRouter.get '/subscription/invites/:token/', AuthenticationController.requireLogin(),
|
||||
TeamInvitesController.viewInvite
|
||||
webRouter.put '/subscription/invites/:token/', AuthenticationController.requireLogin(),
|
||||
webRouter.put '/subscription/invites/:token/',
|
||||
AuthenticationController.requireLogin(),
|
||||
RateLimiterMiddlewear.rateLimit({
|
||||
endpointName: 'team-invite',
|
||||
maxRequests: 10
|
||||
timeInterval: 60
|
||||
}),
|
||||
TeamInvitesController.acceptInvite
|
||||
|
||||
# Routes to join a domain licence team
|
||||
webRouter.get '/user/subscription/domain/join', AuthenticationController.requireLogin(), DomainLicenceController.join
|
||||
webRouter.post '/user/subscription/domain/join', AuthenticationController.requireLogin(), DomainLicenceController.createInvite
|
||||
webRouter.post '/user/subscription/domain/join',
|
||||
AuthenticationController.requireLogin(),
|
||||
RateLimiterMiddlewear.rateLimit({
|
||||
endpointName: 'join-domain-subscription',
|
||||
maxRequests: 10
|
||||
timeInterval: 60
|
||||
}),
|
||||
DomainLicenceController.createInvite
|
||||
|
||||
#recurly callback
|
||||
publicApiRouter.post '/user/subscription/callback', SubscriptionController.recurlyNotificationParser, SubscriptionController.recurlyCallback
|
||||
|
|
|
@ -21,6 +21,7 @@ module.exports = UserEmailsConfirmationHandler =
|
|||
emailOptions =
|
||||
to: email
|
||||
confirmEmailUrl: "#{settings.siteUrl}/user/emails/confirm?token=#{token}"
|
||||
sendingUser_id: user_id
|
||||
EmailHandler.sendEmail emailTemplate, emailOptions, callback
|
||||
|
||||
confirmEmailFromToken: (token, callback = (error) ->) ->
|
||||
|
|
|
@ -122,6 +122,11 @@ module.exports = class Router
|
|||
UserEmailsController.confirm
|
||||
webRouter.post '/user/emails/resend_confirmation',
|
||||
AuthenticationController.requireLogin(),
|
||||
RateLimiterMiddlewear.rateLimit({
|
||||
endpointName: "resend-confirmation"
|
||||
maxRequests: 10
|
||||
timeInterval: 60
|
||||
}),
|
||||
UserEmailsController.resendConfirmation
|
||||
|
||||
if Features.hasFeature 'affiliations'
|
||||
|
@ -326,8 +331,14 @@ module.exports = class Router
|
|||
# webRouter.post "/beta/opt-in", AuthenticationController.requireLogin(), BetaProgramController.optIn
|
||||
# webRouter.post "/beta/opt-out", AuthenticationController.requireLogin(), BetaProgramController.optOut
|
||||
webRouter.get "/confirm-password", AuthenticationController.requireLogin(), SudoModeController.sudoModePrompt
|
||||
webRouter.post "/confirm-password", AuthenticationController.requireLogin(), SudoModeController.submitPassword
|
||||
|
||||
webRouter.post "/confirm-password",
|
||||
AuthenticationController.requireLogin(),
|
||||
RateLimiterMiddlewear.rateLimit({
|
||||
endpointName: "confirm-password"
|
||||
maxRequests: 10
|
||||
timeInterval: 60
|
||||
}),
|
||||
SudoModeController.submitPassword
|
||||
|
||||
# New "api" endpoints. Started as a way for v1 to call over to v2 (for
|
||||
# long-term features, as opposed to the nominally temporary ones in the
|
||||
|
|
|
@ -570,6 +570,7 @@ describe "CollaboratorsInviteController", ->
|
|||
@res.render = sinon.stub()
|
||||
@res.sendStatus = sinon.stub()
|
||||
@CollaboratorsInviteHandler.resendInvite = sinon.stub().callsArgWith(3, null)
|
||||
@CollaboratorsInviteController._checkRateLimit = sinon.stub().yields(null, true)
|
||||
@callback = sinon.stub()
|
||||
@next = sinon.stub()
|
||||
|
||||
|
@ -585,6 +586,9 @@ describe "CollaboratorsInviteController", ->
|
|||
it 'should have called resendInvite', ->
|
||||
@CollaboratorsInviteHandler.resendInvite.callCount.should.equal 1
|
||||
|
||||
it 'should check the rate limit', ->
|
||||
@CollaboratorsInviteController._checkRateLimit.callCount.should.equal 1
|
||||
|
||||
describe 'when resendInvite produces an error', ->
|
||||
|
||||
beforeEach ->
|
||||
|
|
|
@ -51,7 +51,7 @@ describe "PasswordResetController", ->
|
|||
@PasswordResetHandler.generateAndEmailResetToken.callsArgWith(1, null, true)
|
||||
@RateLimiter.addCount.callsArgWith(1, null, false)
|
||||
@res.send = (code)=>
|
||||
code.should.equal 500
|
||||
code.should.equal 429
|
||||
@PasswordResetHandler.generateAndEmailResetToken.calledWith(@email.trim()).should.equal false
|
||||
done()
|
||||
@PasswordResetController.requestReset @req, @res
|
||||
|
|
|
@ -46,6 +46,7 @@ describe "UserEmailsConfirmationHandler", ->
|
|||
.calledWith('confirmEmail', {
|
||||
to: @email,
|
||||
confirmEmailUrl: 'emails.example.com/user/emails/confirm?token=new-token'
|
||||
sendingUser_id: @user_id
|
||||
})
|
||||
.should.equal true
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue