forked from Mirrors/keyoxide-web
feat: add profile request rate limiter
This commit is contained in:
parent
bccd5d298f
commit
b333365730
5 changed files with 50 additions and 8 deletions
|
@ -12,6 +12,7 @@
|
|||
"dotenv": "^16.0.3",
|
||||
"express": "^4.17.1",
|
||||
"express-http-context2": "^1.0.0",
|
||||
"express-rate-limit": "^7.0.1",
|
||||
"express-validator": "^6.13.0",
|
||||
"got": "^11.8.2",
|
||||
"hash-wasm": "^4.9.0",
|
||||
|
|
|
@ -29,18 +29,42 @@ more information on this, and how to apply and follow the GNU AGPL, see <https:/
|
|||
*/
|
||||
import express from 'express'
|
||||
import bodyParserImport from 'body-parser'
|
||||
import { rateLimit } from 'express-rate-limit'
|
||||
import { generateSignatureProfile, utils, generateWKDProfile, generateHKPProfile, generateAutoProfile, generateKeybaseProfile } from '../server/index.js'
|
||||
import { Profile } from 'doipjs'
|
||||
import { getMetaFromReq } from '../server/utils.js'
|
||||
import logger from '../log.js'
|
||||
|
||||
const router = express.Router()
|
||||
const bodyParser = bodyParserImport.urlencoded({ extended: false })
|
||||
|
||||
router.get('/sig', (req, res) => {
|
||||
let profileRateLimiter = (req, res, next) => {
|
||||
next()
|
||||
}
|
||||
|
||||
if (process.env.ENABLE_EXPERIMENTAL_RATE_LIMITER) {
|
||||
profileRateLimiter = rateLimit({
|
||||
windowMs: 1000,
|
||||
limit: 3,
|
||||
standardHeaders: 'draft-7',
|
||||
legacyHeaders: false,
|
||||
handler: (req, res, next, options) => {
|
||||
logger.debug('Rate-limiting a profile request',
|
||||
{ component: 'profile_rate_limiter', action: 'block' })
|
||||
|
||||
res.status(options.statusCode).render('429', { meta: getMetaFromReq(req) })
|
||||
}
|
||||
})
|
||||
|
||||
logger.debug('Starting the profile request rate limiter',
|
||||
{ component: 'profile_rate_limiter', action: 'start' })
|
||||
}
|
||||
|
||||
router.get('/sig', profileRateLimiter, (req, res) => {
|
||||
res.render('profile', { isSignature: true, signature: null, meta: getMetaFromReq(req) })
|
||||
})
|
||||
|
||||
router.post('/sig', bodyParser, async (req, res) => {
|
||||
router.post('/sig', profileRateLimiter, bodyParser, async (req, res) => {
|
||||
const data = await generateSignatureProfile(req.body.signature)
|
||||
const title = utils.generatePageTitle('profile', data)
|
||||
res.set('ariadne-identity-proof', data.identifier)
|
||||
|
@ -55,7 +79,7 @@ router.post('/sig', bodyParser, async (req, res) => {
|
|||
})
|
||||
})
|
||||
|
||||
router.get('/wkd/:id', async (req, res) => {
|
||||
router.get('/wkd/:id', profileRateLimiter, async (req, res) => {
|
||||
const data = await generateWKDProfile(req.params.id)
|
||||
const title = utils.generatePageTitle('profile', data)
|
||||
res.set('ariadne-identity-proof', data.identifier)
|
||||
|
@ -68,7 +92,7 @@ router.get('/wkd/:id', async (req, res) => {
|
|||
})
|
||||
})
|
||||
|
||||
router.get('/hkp/:id', async (req, res) => {
|
||||
router.get('/hkp/:id', profileRateLimiter, async (req, res) => {
|
||||
const data = await generateHKPProfile(req.params.id)
|
||||
const title = utils.generatePageTitle('profile', data)
|
||||
res.set('ariadne-identity-proof', data.identifier)
|
||||
|
@ -81,7 +105,7 @@ router.get('/hkp/:id', async (req, res) => {
|
|||
})
|
||||
})
|
||||
|
||||
router.get('/hkp/:server/:id', async (req, res) => {
|
||||
router.get('/hkp/:server/:id', profileRateLimiter, async (req, res) => {
|
||||
const data = await generateHKPProfile(req.params.id, req.params.server)
|
||||
const title = utils.generatePageTitle('profile', data)
|
||||
res.set('ariadne-identity-proof', data.identifier)
|
||||
|
@ -94,7 +118,7 @@ router.get('/hkp/:server/:id', async (req, res) => {
|
|||
})
|
||||
})
|
||||
|
||||
router.get('/keybase/:username/:fingerprint', async (req, res) => {
|
||||
router.get('/keybase/:username/:fingerprint', profileRateLimiter, async (req, res) => {
|
||||
const data = await generateKeybaseProfile(req.params.username, req.params.fingerprint)
|
||||
const title = utils.generatePageTitle('profile', data)
|
||||
res.set('ariadne-identity-proof', data.identifier)
|
||||
|
@ -107,7 +131,7 @@ router.get('/keybase/:username/:fingerprint', async (req, res) => {
|
|||
})
|
||||
})
|
||||
|
||||
router.get('/:id', async (req, res) => {
|
||||
router.get('/:id', profileRateLimiter, async (req, res) => {
|
||||
const data = await generateAutoProfile(req.params.id)
|
||||
const title = utils.generatePageTitle('profile', data)
|
||||
res.set('ariadne-identity-proof', data.identifier)
|
||||
|
|
|
@ -36,4 +36,8 @@
|
|||
|
||||
# Enable caching of keys (experimental)
|
||||
# Opt-in; to disable, omit the environment variable
|
||||
#ENABLE_EXPERIMENTAL_CACHE=
|
||||
#ENABLE_EXPERIMENTAL_CACHE=true
|
||||
|
||||
# Enable profile request rate limiting (experimental)
|
||||
# Opt-in; to disable, omit the environment variable
|
||||
#ENABLE_EXPERIMENTAL_RATE_LIMITER=true
|
||||
|
|
8
views/429.pug
Normal file
8
views/429.pug
Normal file
|
@ -0,0 +1,8 @@
|
|||
extends templates/base.pug
|
||||
|
||||
block content
|
||||
h1 429 TOO MANY REQUESTS
|
||||
p
|
||||
| Too many requests from this IP, please try again later.
|
||||
br
|
||||
| Limit: 3 profile requests per second.
|
|
@ -2269,6 +2269,11 @@ express-http-context2@^1.0.0:
|
|||
resolved "https://registry.yarnpkg.com/express-http-context2/-/express-http-context2-1.0.0.tgz#58cd9fb0d233739e0dcd7aabb766d1dc74522d77"
|
||||
integrity sha512-xdukoNNpWcuMn5ZJcjDe/tA+2A96rQ1MyAB/oWUU7qP15Tkz3txQyFsw/QG8YgRzTJ1sNAA8Bdq0o5b/1Y4zLA==
|
||||
|
||||
express-rate-limit@^7.0.1:
|
||||
version "7.0.1"
|
||||
resolved "https://registry.yarnpkg.com/express-rate-limit/-/express-rate-limit-7.0.1.tgz#933af24166990ea4fc8004335e6cd6c86fd31562"
|
||||
integrity sha512-oTIPm094gh8c7nbShl4TNLqnayzOcbDGY7dCRnFqUAvptyb0pp5231LaH34JtvVEbZlOJMiixikU5AVK8VN3FA==
|
||||
|
||||
express-validator@^6.10.0, express-validator@^6.13.0:
|
||||
version "6.15.0"
|
||||
resolved "https://registry.yarnpkg.com/express-validator/-/express-validator-6.15.0.tgz#5e4601428960b0d66f5f4ae09cb32ed2077374a4"
|
||||
|
|
Loading…
Reference in a new issue