mirror of
https://framagit.org/les/gancio.git
synced 2025-01-31 16:42:22 +01:00
introduce a new instance api rate limiter
This commit is contained in:
parent
c54630a2f4
commit
a9c9fd38a5
5 changed files with 47 additions and 22 deletions
|
@ -689,7 +689,7 @@ const eventController = {
|
|||
...pagination,
|
||||
replacements
|
||||
}).catch(e => {
|
||||
log.error('[EVENT]', e)
|
||||
log.error('[EVENT]' + String(e))
|
||||
return []
|
||||
})
|
||||
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
const rateLimit = require('express-rate-limit');
|
||||
const log = require('../../log')
|
||||
const nominatim = require('../../services/geocoding/nominatim')
|
||||
const photon = require('../../services/geocoding/photon')
|
||||
|
@ -8,15 +7,6 @@ let d = 0 // departure time
|
|||
let h = 0 // hit geocoding provider time (aka Latency)
|
||||
|
||||
const geocodingController = {
|
||||
/**
|
||||
* TODO: replace/merge with a general 'instance rate-limiter' or 'instance api-related rate-limiter' when this will be defined
|
||||
*/
|
||||
instanceApiRateLimiter: rateLimit({
|
||||
windowMs: 15 * 60 * 1000, // 15 minutes
|
||||
max: 100, // Limit each IP to 100 requests per `window` (here, per 15 minutes)
|
||||
standardHeaders: true, // Return rate limit info in the `RateLimit-*` headers
|
||||
legacyHeaders: false, // Disable the `X-RateLimit-*` headers
|
||||
}),
|
||||
|
||||
/**
|
||||
* Limit provider api usage.
|
||||
|
|
|
@ -3,8 +3,6 @@ const { Place, Event } = require('../models/models')
|
|||
const eventController = require('./event')
|
||||
const exportController = require('./export')
|
||||
|
||||
const { version } = require('../../../package.json')
|
||||
|
||||
const log = require('../../log')
|
||||
const { Op, where, col, fn, cast } = require('sequelize')
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ const oauthController = require('./controller/oauth')
|
|||
const announceController = require('./controller/announce')
|
||||
const pluginController = require('./controller/plugins')
|
||||
const geocodingController = require('./controller/geocoding')
|
||||
const { DDOSProtectionApiRateLimiter, SPAMProtectionApiRateLimiter } = require('./limiter')
|
||||
const helpers = require('../helpers')
|
||||
const storage = require('./storage')
|
||||
|
||||
|
@ -30,6 +31,10 @@ module.exports = () => {
|
|||
api.use(express.urlencoded({ extended: false }))
|
||||
api.use(express.json())
|
||||
|
||||
if (process.env.NODE_ENV !== 'test') {
|
||||
api.use(DDOSProtectionApiRateLimiter)
|
||||
}
|
||||
|
||||
|
||||
if (config.status !== 'READY') {
|
||||
|
||||
|
@ -66,12 +71,12 @@ module.exports = () => {
|
|||
api.get('/ping', (_req, res) => res.sendStatus(200))
|
||||
api.get('/user', isAuth, (req, res) => res.json(req.user))
|
||||
|
||||
api.post('/user/recover', userController.forgotPassword)
|
||||
api.post('/user/recover', SPAMProtectionApiRateLimiter, userController.forgotPassword)
|
||||
api.post('/user/check_recover_code', userController.checkRecoverCode)
|
||||
api.post('/user/recover_password', userController.updatePasswordWithRecoverCode)
|
||||
api.post('/user/recover_password', SPAMProtectionApiRateLimiter, userController.updatePasswordWithRecoverCode)
|
||||
|
||||
// register and add users
|
||||
api.post('/user/register', userController.register)
|
||||
api.post('/user/register', SPAMProtectionApiRateLimiter, userController.register)
|
||||
api.post('/user', isAdmin, userController.create)
|
||||
|
||||
// update user
|
||||
|
@ -127,7 +132,7 @@ module.exports = () => {
|
|||
*/
|
||||
|
||||
// allow anyone to add an event (anon event has to be confirmed, TODO: flood protection)
|
||||
api.post('/event', eventController.isAnonEventAllowed, upload.single('image'), eventController.add)
|
||||
api.post('/event', eventController.isAnonEventAllowed, SPAMProtectionApiRateLimiter, upload.single('image'), eventController.add)
|
||||
|
||||
// api.get('/event/search', eventController.search)
|
||||
|
||||
|
@ -141,8 +146,8 @@ module.exports = () => {
|
|||
api.get('/event/meta', eventController.searchMeta)
|
||||
|
||||
// add event notification TODO
|
||||
api.post('/event/notification', eventController.addNotification)
|
||||
api.delete('/event/notification/:code', eventController.delNotification)
|
||||
// api.post('/event/notification', eventController.addNotification)
|
||||
// api.delete('/event/notification/:code', eventController.delNotification)
|
||||
|
||||
api.post('/settings', isAdmin, settingsController.setRequest)
|
||||
api.get('/settings', isAdmin, settingsController.getAll)
|
||||
|
@ -173,8 +178,8 @@ module.exports = () => {
|
|||
api.put('/place', isAdmin, placeController.updatePlace)
|
||||
|
||||
// - GEOCODING
|
||||
api.get('/placeOSM/Nominatim/:place_details', helpers.isGeocodingEnabled, geocodingController.instanceApiRateLimiter, geocodingController.nominatimRateLimit, geocodingController._nominatim)
|
||||
api.get('/placeOSM/Photon/:place_details', helpers.isGeocodingEnabled, geocodingController.instanceApiRateLimiter, geocodingController.photonRateLimit, geocodingController._photon)
|
||||
api.get('/placeOSM/Nominatim/:place_details', helpers.isGeocodingEnabled, geocodingController.nominatimRateLimit, geocodingController._nominatim)
|
||||
api.get('/placeOSM/Photon/:place_details', helpers.isGeocodingEnabled, geocodingController.photonRateLimit, geocodingController._photon)
|
||||
|
||||
// - TAGS
|
||||
api.get('/tags', isAdmin, tagController.getAll)
|
||||
|
@ -215,7 +220,7 @@ module.exports = () => {
|
|||
// OAUTH
|
||||
api.get('/clients', isAuth, oauthController.getClients)
|
||||
api.get('/client/:client_id', isAuth, oauthController.getClient)
|
||||
api.post('/client', oauthController.createClient)
|
||||
api.post('/client', SPAMProtectionApiRateLimiter, oauthController.createClient)
|
||||
}
|
||||
|
||||
api.use((_req, res) => res.sendStatus(404))
|
||||
|
|
32
server/api/limiter.js
Normal file
32
server/api/limiter.js
Normal file
|
@ -0,0 +1,32 @@
|
|||
const rateLimit = require('express-rate-limit')
|
||||
const log = require('../log')
|
||||
|
||||
const next = (req, res, next) => next()
|
||||
|
||||
const instanceApiRateLimiter = {
|
||||
|
||||
DDOSProtectionApiRateLimiter: (process.env.NODE_ENV === 'test' ? next : rateLimit({
|
||||
windowMs: 60 * 1000, // 5 minutes
|
||||
max: 100, // Limit each IP to 100 requests per `window` (here, per 5 minutes)
|
||||
standardHeaders: true, // Return rate limit info in the `RateLimit-*` headers
|
||||
legacyHeaders: false, // Disable the `X-RateLimit-*` headers
|
||||
handler: (request, response, next, options) => {
|
||||
log.warn(`DDOS protection api rate limiter: > 100req/minute/ip ${request.ip}`)
|
||||
return response.status(options.statusCode).send(options.message)
|
||||
}
|
||||
})),
|
||||
|
||||
SPAMProtectionApiRateLimiter: (process.env.NODE_ENV === 'test' ? next : rateLimit({
|
||||
windowMs: 5 * 60 * 1000, // 10 minutes
|
||||
max: 3, // Limit each IP to 3 requests per `window` (here, per 15 minutes)
|
||||
standardHeaders: true, // Return rate limit info in the `RateLimit-*` headers
|
||||
legacyHeaders: false, // Disable the `X-RateLimit-*` headers
|
||||
handler: (request, response, next, options) => {
|
||||
log.warn(`SPAM protection api rate limiter: 3req/5min/ip ${request.ip}`)
|
||||
return response.status(options.statusCode).send(options.message)
|
||||
}
|
||||
}))
|
||||
|
||||
}
|
||||
|
||||
module.exports = instanceApiRateLimiter
|
Loading…
Reference in a new issue